﻿//-----------------------------------------------------------------------------
//<filedescription file="SccmObjectInstaller.cs" company="Microsoft">
//  <copyright>
//     Copyright © Microsoft Corporation.  All rights reserved.
//     ***  DESIGNATED SAMPLE CODE (per the included software license terms) ***
//      THIS CODE SAMPLE IS MADE AVAILABLE TO YOU WITHOUT WARRANTY OF ANY KIND
//      AND CONFERS NO RIGHTS ON YOU WHATSOEVER EXCEPT THE RIGHT TO REVIEW IT
//      SOLELY AS A REFERENCE.  THE ENTIRE RISK OF USE OR RESULTS FROM USE OF
//      THIS CODE SAMPLE REMAINS WITH YOU.
//  </copyright>
//  <purpose>
//     Sample class for providing an install layer for SCCM so that objects
//     can be installed, removed or updated in SCCM by using an XML file
//     rather than creating new code.
//
//
//     CURRENTLY IN PROCESS OF DEVELOPMENT!!!!!
//
//  </purpose>
//  <notes>
//  </notes>
//</filedescription>
//-----------------------------------------------------------------------------

#region Using directives

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Management;
using System.Net;
using System.Net.Mail;
using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;
using System.Runtime.Remoting.Messaging;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Web;
using System.Windows.Forms;
using System.Xml;
using System.Xml.XPath;
using Microsoft.Win32;
using Microsoft.ConfigurationManagement.AdminConsole;
using Microsoft.ConfigurationManagement.ManagementProvider;
using Microsoft.ConfigurationManagement.AdminConsole.TaskSequenceEditor;
using Microsoft.ConfigurationManagement.AdminConsole.Common;
using Microsoft.ConfigurationManagement.AdminConsole.OsdCommon;
using Microsoft.ConfigurationManagement.ManagementProvider.WqlQueryEngine;

#endregion


namespace Microsoft.ConfigurationManagement.IntegrationDevelopmentKit
{

    #region Structs

    /// <summary>
    /// 
    /// </summary>
    public struct InstallerStatus
    {
        private string currentSection;
        private string statusMessage;
        private SccmObjectInstaller.InstallerReturnValue statusValue;
        private int percentComplete;

        /// <summary>
        /// 
        /// </summary>
        /// <param name="sectionVal"></param>
        /// <param name="statusMsgVal"></param>
        /// <param name="statusTypeVal"></param>
        /// <param name="pctVal"></param>
        public InstallerStatus(string sectionVal, string statusMsgVal, SccmObjectInstaller.InstallerReturnValue statusTypeVal, int pctVal)
        {
            currentSection = sectionVal;
            statusValue = statusTypeVal;
            statusMessage = statusMsgVal;
            percentComplete = pctVal;
            
        }

        /// <summary>
        /// 
        /// </summary>
        public string CurrentSection
        {
            get { return currentSection; }
            set { currentSection = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public string StatusMessage
        {
            get { return statusMessage; }
            set { statusMessage = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public SccmObjectInstaller.InstallerReturnValue StatusValue
        {
            get { return statusValue; }
            set { statusValue = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public int PercentComplete
        {
            get { return percentComplete; }
            set { percentComplete = value; }
        }

        /// <summary>
        /// 
        /// </summary>
        public void ResetStatus()
        {
            currentSection = null;
            statusMessage = null;
            statusValue = SccmObjectInstaller.InstallerReturnValue.Success;
            percentComplete = 0;
        }

    }

    #endregion


    /// <summary>
    /// 
    /// </summary>
    public class SccmObjectInstaller
    {
        #region Constants
        /// <summary>
        /// 
        /// </summary>
        public const string LOGFILENAME = "_Installer.log";
        /// <summary>
        /// 
        /// </summary>
        public const string SECONDARYLOGFILE = "_InstallerDebug.log";
        /// <summary>
        /// 
        /// </summary>
        public const string XMLLOGFILENAME = "_ComponentsInstalled.xml";
        #endregion

        #region Properties

        private IntegrationKitUtilities integrationUtils = new IntegrationKitUtilities();
        
        private XmlDocument installedComponentsXml = new XmlDocument();
        /// <summary>
        /// 
        /// </summary>
        public XmlDocument InstalledComponentsXml
        {
            get { return installedComponentsXml; }
            set { installedComponentsXml = value; }
        }

        private WqlConnectionManager connection;
        /// <summary>
        /// 
        /// </summary>
        public WqlConnectionManager Connection
        {
            get { return connection; }
            set { connection = value; }
        }

        private StringBuilder logString = new StringBuilder();
        /// <summary>
        /// 
        /// </summary>
        public StringBuilder LogString
        {
            get { return logString;}
            set { logString = value;}
        }

        //private StreamWriter logFile;

        ///// <summary>
        /////     
        ///// </summary>
        ///// <value>
        /////     <para>
        /////         
        /////     </para>
        ///// </value>
        ///// <remarks>
        /////     
        ///// </remarks>
        //public StreamWriter LogFile
        //{
        //    get { return logFile; }
        //    set { logFile = value; }
        //}

        private InstallerStatus status = new InstallerStatus();
        /// <summary>
        /// 
        /// </summary>
        public InstallerStatus Status
        {
            get { return status; }
            set { status = value; }
        }

        private string logDirectory;
        /// <summary>
        /// 
        /// </summary>
        public string LogDir
        {
            get { return logDirectory;}
            set { logDirectory = value; }
        }


        private static StreamWriter logFile;

        /// <summary>
        /// Gets or sets file stream object created by the custom action for writing the log file.
        /// </summary>
        public static StreamWriter LogFile
        {
            get { return logFile; }
            set { logFile = value; }
        }

        #endregion

        #region Fields

        
        private string siteCode;

        private string serverName;

        private string adminUIOnlyDir;


        
        #endregion

        #region Enums

        /// <summary>
        /// 
        /// </summary>
        public enum NodeType
        {
            /// <summary>
            /// 
            /// </summary>
            None,
            /// <summary>
            /// 
            /// </summary>
            Folder,
            /// <summary>
            /// 
            /// </summary>
            Collection,
            /// <summary>
            /// 
            /// </summary>
            Package,
            /// <summary>
            /// 
            /// </summary>
            Program,
            /// <summary>
            /// 
            /// </summary>
            Advertisement,
            /// <summary>
            /// 
            /// </summary>
            Driver,
            /// <summary>
            /// 
            /// </summary>
            DriverPackage,
            /// <summary>
            /// 
            /// </summary>
            DriverCategory,
            /// <summary>
            /// 
            /// </summary>
            BootImagePackage,
            /// <summary>
            /// 
            /// </summary>
            OSInstallPackage,
            /// <summary>
            /// 
            /// </summary>
            OSImagePackage,
            /// <summary>
            /// 
            /// </summary>
            TaskSequence,
            /// <summary>
            /// 
            /// </summary>
            TaskSequencePackage,
            /// <summary>
            /// 
            /// </summary>
            DcmBaseline,
            /// <summary>
            /// 
            /// </summary>
            DcmConfigurationItem,
            /// <summary>
            /// 
            /// </summary>
            SoftwareUpdate,
            /// <summary>
            /// 
            /// </summary>
            Report,
            /// <summary>
            /// 
            /// </summary>
            Query
        }
        
        /// <summary>
        /// 
        /// </summary>
        public enum InstallerReturnValue
        {
            /// <summary>
            /// 
            /// </summary>
            Success = 0,
            /// <summary>
            /// 
            /// </summary>
            Error,
            /// <summary>
            /// 
            /// </summary>
            NoDataFound,
            /// <summary>
            /// 
            /// </summary>
            InvalidParameter,
            /// <summary>
            /// 
            /// </summary>
            ConnectionInvalid,
            /// <summary>
            /// 
            /// </summary>
            Exception,
            /// <summary>
            /// 
            /// </summary>
            Other
        }

        
        #endregion

        #region Constructor

        /// <summary>
        /// 
        /// </summary>
        public SccmObjectInstaller()
        {
            //default constructor
           
        }

        #endregion
        
        #region Methods

        /// <summary>
        /// 
        /// </summary>
        /// <param name="configFile"></param>
        /// <param name="logDir"></param>
        /// <param name="logReturn"></param>
        /// <returns></returns>
        public int InstallComponentsFromXmlFile(string configFile, string logDir, out string logReturn)
        {
            try
            {
                logReturn = string.Empty;
                int returnCode = 0;

                WriteLog("Integration Kit version [" + IntegrationKitUtilities.GetAssemblyVersion(typeof(SccmObjectInstaller)) + "], Dated [" + IntegrationKitUtilities.GetAssemblyDate(typeof(SccmObjectInstaller)) + "]");

                if (string.IsNullOrEmpty(configFile))
                {
                    WriteLog("configFile parameter was null!");
                    logReturn = (string)LogString.ToString(); 
                    throw new ArgumentNullException("configFile");
                }
                configFile = configFile.Trim();

                WriteLog("configFile parameter was: " + configFile); 
                if (string.IsNullOrEmpty(logDir))
                {
                    WriteLog("logDir parameter was null! Setting to current directory.");
                    logDir = Directory.GetCurrentDirectory();
                }
                WriteLog("logDir parameter was: " + logDir);

                LogDir = logDir;
                
                WriteLog("Setting LogFile to " + SECONDARYLOGFILE);
                LogFile = new StreamWriter(SECONDARYLOGFILE);

                WriteLog("Setting IntegrationKitUtilities.LogFile to " + SECONDARYLOGFILE); 
                IntegrationKitUtilities.LogFile = LogFile;
                IntegrationKitUtilities.DebugEnabled = true;

                WriteLog("Replacing nulls at the end of the configFile path");
                
                configFile = configFile.Replace("\0", "");

                if (File.Exists(configFile) == false)
                {
                    WriteLog("Xml file not found: [" + configFile + "]");
                    logReturn = (string)LogString.ToString();
                    //SaveLogToFile(LOGFILENAME, LogString.ToString(), FileMode.Append);
                    return 1001;
                }
                WriteLog(" ");
                WriteLog("=================================================================================================");
                WriteLog("Processing XML file: " + configFile);
                WriteLog(" ");
                WriteLog("Current Directory: " + Directory.GetCurrentDirectory());


                XmlDocument xml = new XmlDocument();
                try
                {
                    xml.Load(configFile);
                }
                catch (XmlException ex)
                {
                    WriteError("Xml exception occurred loading the file: " + configFile);
                    WriteError(ex.Message + "\n" + ex.StackTrace + "\n" + +ex.LineNumber);
                    logReturn = (string)LogString.ToString();
                    //SaveLogToFile(LOGFILENAME, LogString.ToString(), FileMode.Append);
                    return 1002;
                }
                returnCode = (int)ProcessXmlFile(xml);
                if (returnCode != 0)
                {
                    WriteError("Processing the XML file exited with an error (" + returnCode + ")");
                    WriteError("File in process: " + configFile);
                    logReturn = (string)LogString.ToString();
                    DumpSecondaryLog();
                    returnCode = 1001;
                }
                else
                {
                    WriteLog(" ");
                    WriteLog(" ");
                    WriteLog("Completed processing the XML file : " + configFile);
                    WriteLog("=================================================================================================");
                    WriteLog(" ");
                }
                logReturn = (string)LogString.ToString();
                //SaveLogToFile(LOGFILENAME, LogString.ToString(), FileMode.Append);
                SaveLogToFile(XMLLOGFILENAME, InstalledComponentsXml.OuterXml, FileMode.Create);
                DumpSecondaryLog();
                return returnCode;
            }
            catch(Exception ex)
            {
                WriteLog("\n\n================================================================================[ ERROR ]=================");
                WriteLog("Exception occurred during the processing of this XML. Details below.");
                WriteLog(ex.Message);
                WriteLog(ex.StackTrace);
                WriteLog(ex.Data.ToString());
                WriteLog(ex.HelpLink);
                WriteLog(ex.InnerException.ToString());
                WriteLog(ex.Source);
                WriteLog("Member: " + ex.TargetSite.Module + "\t" + ex.TargetSite.Name);
                WriteLog("Method Attributes: " + ex.TargetSite.Attributes.ToString());
                string paramsString = string.Empty;
                ParameterInfo[] paramsInfo = ex.TargetSite.GetParameters();
                foreach (ParameterInfo param in paramsInfo)
                {
                    paramsString += "\n\tName & Type: " + param.ToString() + "\n\tAttributes:" + param.Attributes.ToString();
                }
                WriteLog("Method Parameters: " + paramsString);

                WriteLog("================================================================================[ ERROR ]=================\n\n");
                logReturn = (string)LogString.ToString();
                //SaveLogToFile(LOGFILENAME, LogString.ToString(), FileMode.Append);
                SaveLogToFile(XMLLOGFILENAME, InstalledComponentsXml.OuterXml, FileMode.Create);
                DumpSecondaryLog();
                return 3;
            }

        }

        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="configFile"></param>
        ///// <param name="log"></param>
        ///// <returns></returns>
        //public int RollbackComponentsFromXmlFile(string configFile, string logDir, out string log)
        //{
        //    try
        //    {
        //        log = null;
        //        int returnCode = 0;

        //        if (string.IsNullOrEmpty(logDir) == false)
        //        {
        //            if (Directory.Exists(logDir))
        //            {
        //                LogDir = logDir;
        //                WriteLog("Log file directory is set to: " + LogDir);
        //            }
        //            else
        //            {
        //                LogDir = @"C:\";
        //                WriteLog(@"Log file directory not found: " + logDir);
        //                WriteLog(@"Logging to root C:\ drive");
        //            }
        //        }

        //        configFile = configFile.Replace("\0", "");

        //        if (File.Exists(configFile) == false)
        //        {
        //            WriteLog("Xml file not found: [" + configFile + "]");
        //            log = (string)LogString.ToString();
        //            //SaveLogToFile(LOGFILENAME, LogString.ToString(), FileMode.Append);
        //            return 0;
        //        }
        //        WriteLog(" ");
        //        WriteLog("=================================================================================================");
        //        WriteLog("Starting REMOVAL process for XML file: " + configFile);
        //        WriteLog(" ");
        //        WriteLog(" NOTE: NO ERRORS WILL BE RETURNED FROM THIS PROCESS - THIS IS TO AVOID LEAVING THE PRODUCT IN");
        //        WriteLog("       A HALF-INSTALLED STATE WHICH CANNOT BE CURED WITHOUT EDITING THE REGISTRY.");
        //        WriteLog(" ");
        //        WriteLog("Current Directory: " + Directory.GetCurrentDirectory());


        //        XmlDocument xml = new XmlDocument();
        //        try
        //        {
        //            xml.Load(configFile);
        //        }
        //        catch (XmlException ex)
        //        {
        //            WriteLog("Xml exception occurred loading the file: " + configFile);
        //            WriteLog(ex.Message + "\n" + ex.StackTrace + "\n" + +ex.LineNumber);
        //            log = (string)LogString.ToString();
        //            //SaveLogToFile(LOGFILENAME, LogString.ToString(), FileMode.Append);
        //            return 0;
        //        }

        //        WriteLog("Changing 'Create' verbs in XML to 'Delete'"); 
        //        xml = ReverseInstallationVerbsInXml(xml);
        //        if (xml == null)
        //        {
        //            WriteLog("An error occurred while trying to modify the XML or no 'Create' actions found");
        //            returnCode = 0;
        //        }
        //        else
        //        {
        //            returnCode = (int)ProcessXmlFile(xml);
        //            if (returnCode != 0)
        //            {
        //                WriteError("Processing the XML file exited with an error (" + returnCode + ") - file: " + configFile);
        //            }
        //            else
        //            {
        //                WriteLog(" ");
        //                WriteLog(" ");
        //                WriteLog("Completed processing the XML file : " + configFile);
        //                WriteLog("=================================================================================================");
        //                WriteLog(" ");
        //            }
        //        }
        //        log = (string)LogString.ToString();
        //        //SaveLogToFile(LOGFILENAME, LogString.ToString(), FileMode.Append);
        //        SaveLogToFile(XMLLOGFILENAME, InstalledComponentsXml.OuterXml, FileMode.Create);
        //        return 0;
        //    }
        //    catch (Exception ex)
        //    {
        //        WriteLog("================================================================================[ ERROR ]=================");
        //        WriteLog("Exception occurred during the processing of this XML. Details below.");
        //        WriteLog(ex.Message);
        //        WriteLog(ex.StackTrace);
        //        WriteLog(ex.Data.ToString());
        //        WriteLog(ex.HelpLink);
        //        WriteLog(ex.InnerException.ToString());
        //        WriteLog(ex.Source);
        //        WriteLog("Member: " + ex.TargetSite.Name);
        //        WriteLog("Method Attributes: " + ex.TargetSite.Attributes.ToString());
        //        WriteLog("Method Parameters: " + ex.TargetSite.GetParameters().ToString());

        //        WriteLog("================================================================================[ ERROR ]=================");
        //        log = (string)LogString.ToString();
        //        //SaveLogToFile(LOGFILENAME, LogString.ToString(), FileMode.Append);
        //        SaveLogToFile(XMLLOGFILENAME, InstalledComponentsXml.OuterXml, FileMode.Create);
        //        return 0;
        //    }
        //}

        ///// <summary>
        ///// 
        ///// </summary>
        ///// <param name="doc"></param>
        ///// <returns></returns>
        //private XmlDocument ReverseInstallationVerbsInXml(XmlDocument doc)
        //{
        //    try
        //    {
        //        if (doc == null)
        //        {
        //            return null;
        //        }
        //        XmlNodeList createNodes = IntegrationKitUtilities.GetXmlNodeList(doc, "//*[@Action='Create']");
        //        XmlNodeList createFromInfNodes = IntegrationKitUtilities.GetXmlNodeList(doc, "//*[@Action='CreateFromInf']");
        //        XmlNodeList createFromOemNodes = IntegrationKitUtilities.GetXmlNodeList(doc, "//*[@Action='CreateFromOem']");
        //        if ((createNodes == null) && (createFromInfNodes == null) && (createFromOemNodes == null))
        //        {
        //            WriteLog("No 'Create' actions found in this XML");
        //            return null; 
        //        }
        //        else
        //        {
        //            if (createNodes != null)
        //            {
        //                WriteLog("Changing 'Create' actions to 'Delete'");
        //                foreach (XmlNode createNode in createNodes)
        //                {
        //                    IntegrationKitUtilities.SetXmlAttribute(createNode, "Action", "Delete");
        //                }
        //            }
        //            if (createFromInfNodes != null)
        //            {
        //                WriteLog("Changing 'CreateFromInf' actions to 'Delete'");
        //                foreach (XmlNode createInfNode in createFromInfNodes)
        //                {
        //                    IntegrationKitUtilities.SetXmlAttribute(createInfNode, "Action", "Delete");
        //                }
        //            }
        //            if (createFromOemNodes != null)
        //            {
        //                WriteLog("Changing 'CreateFromOem' actions to 'Delete'");
        //                foreach (XmlNode createOemNode in createFromOemNodes)
        //                {
        //                    IntegrationKitUtilities.SetXmlAttribute(createOemNode, "Action", "Delete");
        //                }
        //            }
        //            return doc;
        //        }
        //    }
        //    catch
        //    {
        //        WriteLog("Exception occurred in ReverseInstallationVerbsInXml ");
        //        WriteLog(" ");
        //        throw;
        //    }
        //}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        protected InstallerReturnValue ProcessXmlFile(XmlDocument xml)
        {
            if (xml == null)
            {
                WriteError("XML document object passed in was null");
                return InstallerReturnValue.InvalidParameter;
            }
            
            XmlNode topNode = IntegrationKitUtilities.GetXmlNode(xml, "//InstallConfiguration");
            if (topNode == null)
            {
                WriteError("XML file passed in was not a valid installer XML file.");
                return InstallerReturnValue.InvalidParameter;
            }
            
            if (SetupInstall() != InstallerReturnValue.Success)
            {
                return InstallerReturnValue.Error;
            }


            WriteLog("Beginning processing of Configuration Manager objects");
           
            
            #region 000 - Process MOF files

            
            XmlNodeList mofFiles = IntegrationKitUtilities.GetXmlNodeList(xml, "//ImportMofFile");
            if ((mofFiles == null) || (mofFiles.Count == 0))
            {
                WriteLog("No MOF files to process.");
            }
            else
            {
                if (ProcessMofFiles(mofFiles) != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }
                //WriteLog("ProcessMofFiles() returned 'Success'");
            }


            //===[ begin modification ]======================================
            // Modified 9/24/08 by rhearn
            // - Added code to process UpdateDialogsHelpInfo element in XML

            XmlNodeList helpUpdates = IntegrationKitUtilities.GetXmlNodeList(xml, "//UpdateDialogsHelpInfo");
            if ((helpUpdates == null) || (helpUpdates.Count == 0))
            {
                WriteLog("No updates to process for DialogsHelpInfo.xml.");
            }
            else
            {
                if (UpdateDialogsHelpInfo(helpUpdates) != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }
                //WriteLog("ProcessMofFiles() returned 'Success'");
            }
            //===[ end modification ]======================================


            #endregion

            #region 100 - Process Folders

            XmlNode foldersNode = IntegrationKitUtilities.GetXmlNode(xml, "//Folders");
            if (foldersNode == null)
            {
                WriteLog("No folders to process.");
            }
            else
            {
                if (ProcessFolders(foldersNode) != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }
                //WriteLog("ProcessFolders() returned 'Success'");
            }



            #endregion
            
            #region 300 - Process Packages


            XmlNode packagesNode = IntegrationKitUtilities.GetXmlNode(xml, "//Packages");
            if (packagesNode == null)
            {
                WriteLog("No packages, boot images, or OS images to process.");
            }
            else
            {
                if (ProcessPackages(packagesNode) != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }
                //WriteLog("ProcessPackages() returned 'Success'");
            }

            #endregion

            #region 500 - Process Drivers


            XmlNode driversNode = IntegrationKitUtilities.GetXmlNode(xml, "//Drivers");
            if (driversNode == null)
            {
                WriteLog("No drivers, driver packages or categories to process.");
            }
            else
            {
                if (ProcessDrivers(driversNode) != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }
                //WriteLog("ProcessDrivers() returned 'Success'\n");
            }


            #endregion

            #region 600 - Process CustomActions


            XmlNode actionsNode = IntegrationKitUtilities.GetXmlNode(xml, "//CustomActions");
            if (actionsNode == null)
            {
                WriteLog("No custom actions to process.");
            }
            else
            {
                if (ProcessCustomActions(actionsNode) != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }
                //WriteLog("ProcessCustomActions() returned 'Success'\n");
            }


            #endregion

           
            
            //WriteLog("Completed processing the XML file." );
            
            //WriteLog("Saving the Xml Log from the installation to 'SetupLog.xml'");

            //IntegrationKitUtilities.ExportTextFileNoDialog("SetupLog.xml", InstalledComponentsXml.OuterXml);

            //WriteLog("Done!\n\n\n");
                        

            return InstallerReturnValue.Success;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected InstallerReturnValue SetupInstall()
        {

            WriteLog(Properties.Resources.Installer_Section_Setup);
            //===[ begin modifications ]=================================
            // Modified 9/10/08 by rhearn
            // - Added new code for x64 detection and redirection of registry keys to Wow6432Node key

            serverName = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Site Server");
            siteCode = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Site Code");
            adminUIOnlyDir = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Setup", "UI Installation Directory");

            //===[ end modifications ]=================================

            if (string.IsNullOrEmpty(adminUIOnlyDir) == false)
            {
                //this is an adminUI-only installation. No SCCM connection possible
                // get the server name from a different key:
                // HKLM\Software\microsoft\ConfigMgr\AdminUI\Connection\Server
                // serverName = IntegrationKitUtilities.GetSafeRegistryStringValue("HKLM", "Software\\Microsoft\\ConfigMgr\\AdminUI\\Connection", "Server");

                // NOTE: this is being skipped for now so that a username/password is not required during install

            }
            if ((string.IsNullOrEmpty(serverName) == false) && (SetupConnection(serverName) != InstallerReturnValue.Success))
            {
                WriteLog("Could not get a conection to the Configuration Manager server");
                WriteLog("Server name: '" + serverName + "'");
                WriteLog("Site code  : '" + siteCode + "'");
                return InstallerReturnValue.ConnectionInvalid;
            }
            WriteLog("Connected to the Configuration Manager server : " + serverName);
            WriteLog("Site code  : '" + siteCode + "'");
                
            
            InstalledComponentsXml = null;
            XmlDocument xmlLog = new XmlDocument();

            WriteLog("Configuring the Installed Components XML file");

            if (File.Exists(XMLLOGFILENAME))
            {
                try
                {
                    xmlLog.Load(XMLLOGFILENAME);
                    WriteLog("Successfully loaded the file: " + XMLLOGFILENAME);
                }
                catch (XmlException ex)
                {
                    WriteLog("Found the file (" + XMLLOGFILENAME + "), but an XML exception occurred when loading it." );
                    WriteLog(ex.Message + "\n" + ex.StackTrace + "\n" + +ex.LineNumber);
                    //SaveLogToFile(LOGFILENAME, LogString.ToString(), FileMode.Append);
                    return InstallerReturnValue.Error;
                }
            }
            else
            {
                WriteLog("The Installed Components XML file was not found: " + XMLLOGFILENAME + ". Creating a new file");
                string xmlString = "<?xml version=\"1.0\" encoding=\"utf-8\" ?><InstallationLog></InstallationLog>";
                xmlLog.LoadXml(xmlString);
            }
            InstalledComponentsXml = xmlLog;

            return InstallerReturnValue.Success;
            
        }
        

        #region Processing of Major XML Sections


        /// <summary>
        /// 
        /// </summary>
        /// <param name="serverName"></param>
        /// <returns></returns>
        protected InstallerReturnValue SetupConnection(string serverName)
        {
            Connection = IntegrationKitUtilities.Connect(serverName, null, null);
            if (Connection == null)
            {
                WriteLog("Connection was not set properly. Cannot continue.");
                return InstallerReturnValue.ConnectionInvalid;
            }
            //WriteLog("Successfully set up connection to the Configuration Manager server");
            return InstallerReturnValue.Success;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="mofFiles"></param>
        /// <returns></returns>
        protected InstallerReturnValue ProcessMofFiles(XmlNodeList mofFiles)
        {
            try
            {
                WriteLog(Properties.Resources.Installer_Section_MOF);

                if ((mofFiles == null) || (mofFiles.Count == 0))
                {
                    WriteLog("mofFiles parameter passed in to ProcessMofFiles was null. Cannot continue.");
                    return InstallerReturnValue.InvalidParameter;
                }

                
                WriteLog("Found " + mofFiles.Count + " MOF files to process.");
                for (int i = 0; i < mofFiles.Count; i++)
                {

                    string fileName = IntegrationKitUtilities.GetXmlAttribute(mofFiles[i], "FileName");
                    WriteLog("Now processing MOF file " + (i + 1) + " of " + mofFiles.Count + " : " + fileName);

                    string action = IntegrationKitUtilities.GetXmlAttribute(mofFiles[i], "Action");

                    WriteLog("Action to perform: " + action);
                    
                    if (string.Compare(action, "Create", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                       
                        XmlNode pathNode = IntegrationKitUtilities.GetXmlNode(mofFiles[i], "./Path");
                        string path = IntegrationKitUtilities.GetXmlNodeValue(mofFiles[i], "./Path");
                        path = ParseRelativePath(path, pathNode);
                        if (string.IsNullOrEmpty(path))
                        {
                            WriteLog("Error! File path was null after parsing relative path info!\n");
                            return InstallerReturnValue.Error;
                        }

                        if (string.IsNullOrEmpty(fileName))
                        {
                            WriteLog("Error! MOF file name was empty.");
                            return InstallerReturnValue.InvalidParameter;
                        }
                        string filePath = path + Path.DirectorySeparatorChar + fileName;
                        filePath = filePath.Trim();
                        FileInfo fiMof = new FileInfo(filePath);
                        //WriteLog("Fileinfo: '" + fiMof.FullName + "'.");
                        if (File.Exists(filePath) == false)
                        {
                            WriteLog("File '" + filePath + "' was not found. Cannot continue.");
                            return InstallerReturnValue.InvalidParameter;
                        }
                        //WriteLog("Found and processing MOF: " + filePath);

                        string parameterReplacement = IntegrationKitUtilities.GetXmlAttribute(mofFiles[i], "ReplaceVariables");
                        if (string.Compare(parameterReplacement, "true", StringComparison.OrdinalIgnoreCase) == 0)
                        {
                            //perform parameter replacement in the MOF file. For now, the only supported variable is %REPLACESITECODE%

                            WriteLog("Replacing parameters with site code: " + siteCode);
                            string mofContents = IntegrationKitUtilities.ImportTextFileNoDialog(filePath);
                            if (string.IsNullOrEmpty(mofContents))
                            {
                                WriteLog("File " + filePath + " did not have any contents. Cannot process.");
                                return InstallerReturnValue.InvalidParameter;
                            }

                            mofContents = mofContents.Replace("REPLACESITECODE", siteCode);
                            if (IntegrationKitUtilities.ExportTextFileNoDialog(filePath, mofContents) == false)
                            {
                                WriteLog("Failed to write file " + filePath + " successfully. Cannot continue.");
                                return InstallerReturnValue.InvalidParameter;
                            }
                            WriteLog("Finished replacing parameters with site code: " + siteCode);
                        }
                        //utilize the automatic MOF registration feature by placing the MOF file into %SystemRoot%\system32\wbem\mof
                        //when the file is processed, if places the file in the \good or \bad directory

                        //===[ begin modification ]=================
                        // Modified 9/10/08 by rhearn
                        // - Added additional value checking here to ensure paths are available before trying to use
                        // - Added additional logging
                        // - Also modified code path to try running mofcomp.exe if file copy fails
                        bool runMofComp = false;

                        string systemDirectory = Environment.GetFolderPath(Environment.SpecialFolder.System);
                        string wbemDirectory = string.Empty;
                        string autoMofDirectory = string.Empty;
                        string autoMofBadDirectory = string.Empty;
                        string autoMofGoodDirectory = string.Empty;

                        if (Directory.Exists(systemDirectory + @"\wbem"))
                        {
                            wbemDirectory = systemDirectory + @"\wbem\";
                            WriteLog("Wbem directory exists: (" + wbemDirectory + ")");


                            if (Directory.Exists(systemDirectory + @"\wbem\mof"))
                            {
                                autoMofDirectory = systemDirectory + @"\wbem\mof\";

                                if (Directory.Exists(systemDirectory + @"\wbem\mof\bad"))
                                {
                                    autoMofBadDirectory = systemDirectory + @"\wbem\mof\bad\";
                                    if (File.Exists(autoMofBadDirectory + fiMof.Name))
                                    {
                                        try
                                        {
                                            WriteLog("Found existing " +  fiMof.Name + " in " + systemDirectory + @"\wbem\mof\bad. Deleting the file");
                                            File.Delete(autoMofBadDirectory + fiMof.Name);
                                        }
                                        catch (UnauthorizedAccessException)
                                        {
                                            WriteLog("Unable to delete. Not a fatal error.");
                                            //do nothing
                                        }
                                    }
                                }
                                else
                                {
                                     WriteLog(@"Wbem\mof\bad directory does not exist! (" + systemDirectory + @"\wbem\mof\bad)");
                                     WriteLog("Will try using mofcomp.exe instead");
                                     runMofComp = true;
                                }

                                if (Directory.Exists(systemDirectory + @"\wbem\mof\good"))
                                {
                                    autoMofGoodDirectory = systemDirectory + @"\wbem\mof\good\";
                                    if (File.Exists(autoMofGoodDirectory + fiMof.Name))
                                    {
                                        try
                                        {
                                            WriteLog("Found existing " + fiMof.Name + " in " + systemDirectory + @"\wbem\mof\good. Deleting the file");
                                            File.Delete(autoMofGoodDirectory + fiMof.Name);
                                        }
                                        catch (UnauthorizedAccessException)
                                        {
                                            WriteLog("Unable to delete. Not a fatal error.");
                                            //do nothing
                                        }
                                    }
                                }
                                else
                                {
                                    WriteLog(@"Wbem\mof\good directory does not exist! (" + systemDirectory + @"\wbem\mof\good)");
                                    WriteLog("Will try using mofcomp.exe instead");
                                    runMofComp = true;
                                }
                            }
                            else
                            {
                                WriteLog(@"Wbem\mof directory does not exist! (" + systemDirectory + @"\wbem\mof)");
                                WriteLog("Will try using mofcomp.exe instead");
                                runMofComp = true;
                            }
                        }
                        else
                        {
                            WriteLog("Wbem directory does not exist! (" + systemDirectory + @"\wbem)");
                        }
                        
                        // Placed this outer IF statement in here so that if the code above did not find the directory structure needed, 
                        // then it will bypass trying to copy the file and go straight to using mofcomp.exe
                        if (runMofComp == false)
                        {
                            WriteLog("Placing the MOF file into the '" + autoMofDirectory + "' directory to auto-compile into WMI.");
                            try
                            {
                                File.Copy(filePath, autoMofDirectory + fiMof.Name, true);
                                
                                // Moved the rest of the file copy procedure into the "try" statement so it runs on successful copy
                                // and doesn't run if copy fails (catch was modified not to exit the method)

                                WriteLog("Copied MOF file to " + autoMofDirectory + ".");
                                WriteLog("Waiting 10 seconds to check for automatic MOF compilation. (Auto-compile may not be active)");

                                FileSystemWatcher fwGood = new FileSystemWatcher(autoMofDirectory, fiMof.Name);
                                WaitForChangedResult result = fwGood.WaitForChanged(WatcherChangeTypes.Deleted, 10000);
                                if (result.TimedOut == true)
                                {
                                    //timed out waiting for the file to be moved - failed!
                                    WriteLog("Timed out while waiting for the MOF file to automatically import from " + autoMofDirectory);
                                    WriteLog("It's likely that automatic compilation is not enabled (since it is actually a deprecated function)");
                                    runMofComp = true;
                                }
                                else if (result.ChangeType == WatcherChangeTypes.Deleted)
                                {
                                    if (File.Exists(autoMofGoodDirectory + fiMof.Name))
                                    {
                                        WriteLog("MOF file successfully auto-compiled from " + autoMofDirectory + ".");
                                        return InstallerReturnValue.Success;
                                    }
                                    else if (File.Exists(autoMofBadDirectory + fiMof.Name))
                                    {
                                        WriteLog("The MOF compiler flagged the MOF file as bad. The file is located at " + autoMofBadDirectory + fiMof.Name);
                                        return InstallerReturnValue.Error;
                                    }
                                }
                                else
                                {
                                    WriteLog("The MOF compiler removed the MOF file from " + autoMofDirectory + " but never placed it in the 'good' or 'bad' directory.");
                                    WriteLog("If there are problems using the imported component, you should investigate the reason why this occurred.");
                                    WriteLog("Trying to use mofcomp.exe instead.");
                                    // changed this to try mofcomp.exe if auto-import failed instead of exiting.
                                    //return InstallerReturnValue.Error; 
                                    runMofComp = true; 
                                    
                                }
                            }
                            catch (Exception ex)
                            {
                                WriteLog("Failed to copy file " + filePath + " successfully to " + autoMofDirectory + ". Cannot continue.\n\nException info: \n" + ex.Data + "\n" + ex.Message);
                                // changed this to simply try mofcomp.exe if file copy failed instead of exiting.
                                //return InstallerReturnValue.InvalidParameter;
                                runMofComp = true;
                            }
                        }

                        if (runMofComp == true)
                        {
                            string mofcomp = string.Empty;
                            if (File.Exists(wbemDirectory + "mofcomp.exe"))
                            {
                                mofcomp = wbemDirectory + "mofcomp.exe";
                                WriteLog("Found MofComp at: " + mofcomp);
                            }
                            else
                            {
                                WriteLog("MofComp.exe was not found in directory " + wbemDirectory);
                                return InstallerReturnValue.Error;
                            }
                            
                            string mofName = "\"" + fiMof.FullName + "\"";
                            string stdOut = string.Empty;
                            WriteLog("Running MofComp.exe to compile the MOF file");
                            int retVal = RunCommandLine.RunExe(mofcomp, "", mofName, 10000, out stdOut);
                            WriteLog(stdOut);

                            if (retVal != 0)
                            {
                                WriteLog("Error occurred while running MofComp!");
                                return InstallerReturnValue.Error;
                            }
                            WriteLog("Successfully compiled the MOF file");

                            return InstallerReturnValue.Success;
                        }

                        //===[ end modification ]=================
                        
                        
                    }
                    else if (string.Compare(action, "Delete", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        WriteLog("WMI Class removal not yet implemented. Skipping.");
                        //
                        //
                        //  Removing WMI classes not yet implemented
                        //
                        //
                        //
                    }
                }
                return InstallerReturnValue.Success;
            }
            catch
            {
                WriteLog("Exception occurred in ProcessMofFiles ");
                WriteLog(" ");
                return InstallerReturnValue.Error; 
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="foldersNode"></param>
        /// <returns></returns>
        protected InstallerReturnValue ProcessFolders(XmlNode foldersNode)
        {
            WriteLog(Properties.Resources.Installer_Section_Folders);           
                
            if (foldersNode == null)
            {
                WriteLog("foldersNode parameter passed in to ProcessFolders was null. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            if (Connection == null)
            {
                WriteLog("Connection to SCCM server is not valid. Cannot continue.");
                return InstallerReturnValue.ConnectionInvalid;
            }
            if (foldersNode.HasChildNodes == false)
            {
                WriteLog("foldersNode parameter passed in had no child nodes. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
                
            for (int i = 0; i < foldersNode.ChildNodes.Count; i++)
            {
                WriteLog("Processing folder " + (i+1) + " of " + foldersNode.ChildNodes.Count);
                
                if (foldersNode.ChildNodes[i].NodeType == XmlNodeType.Comment)
                {
                    WriteLog("XML node was commented out - skipping.");
                }
                else
                {
                    string action = IntegrationKitUtilities.GetXmlAttribute(foldersNode.ChildNodes[i], "Action");

                    if (ProcessFolder(foldersNode.ChildNodes[i], action) != InstallerReturnValue.Success)
                    {
                        WriteLog("ProcessFolder returned an error. Cannot continue.");
                        return InstallerReturnValue.Error;
                    }
                }
            }
            return InstallerReturnValue.Success;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="packagesNode"></param>
        /// <returns></returns>
        protected InstallerReturnValue ProcessPackages(XmlNode packagesNode)
        {
            if (packagesNode == null)
            {
                WriteLog("packagesNode parameter passed in to ProcessPackages was null. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            if (packagesNode.HasChildNodes == false)
            {
                WriteLog("packagesNode parameter passed in had no child nodes. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }

            
            for (int i = 0; i < packagesNode.ChildNodes.Count; i++)
            {

                
                int percent = Convert.ToInt32(i / packagesNode.ChildNodes.Count);
                
                XmlNode node = packagesNode.ChildNodes[i];
                if (node.NodeType == XmlNodeType.Comment)
                {
                    WriteLog("This node is a comment. Skipping"); 
                    continue;
                }

                WriteLog("Processing " + (i + 1) + " of " + packagesNode.ChildNodes.Count + " package nodes\n");

                string action = IntegrationKitUtilities.GetXmlAttribute(packagesNode.ChildNodes[i], "Action");
                
                switch (node.Name)
                {
                    case "SWDPackage":
                        //SetStatusMessage(Properties.Resources.Installer_Section_Packages, "", InstallerReturnValue.Success, percent);
                        
                        if (ProcessSWDPackage(node, action) != InstallerReturnValue.Success)
                        {
                            WriteLog("ProcessSWDPackage returned an error. Cannot continue.");
                            return InstallerReturnValue.Error;
                        }
                        break;

                    case "BootImagePackage":
                        //SetStatusMessage(Properties.Resources.Installer_Section_BootImages, "", InstallerReturnValue.Success, percent);
                        
                        if (ProcessBootImagePackage(node, action) != InstallerReturnValue.Success)
                        {
                            WriteLog("ProcessBootImagePackage returned an error. Cannot continue.");
                            return InstallerReturnValue.Error;
                        } 
                        break;


                    case "BootImagePackage_InjectChanges":
                        //SetStatusMessage(Properties.Resources.Installer_Section_BootImages, "", InstallerReturnValue.Success, percent);
                        if (ProcessBootImageInjection(node) != InstallerReturnValue.Success)
                        {
                            WriteLog("ProcessBootImageInjection returned an error. Cannot continue.");
                            return InstallerReturnValue.Error;
                        } 
                        break;

                    case "Image_Update":
                        //
                        //
                        // TBD
                        //
                        //
                        break;

                    case "AddChangeNotification":
                        //
                        //
                        // TBD
                        //
                        //
                        break;

                    case "AddDistributionPoints":
                        //
                        //
                        // TBD
                        //
                        //
                        break;

                    case "RefreshPackageSource":
                        //
                        //
                        // TBD
                        //
                        //
                        break;

                    case "Unlock":
                        //
                        //
                        // TBD
                        //
                        //
                        break;

                    default:
                        WriteLog("Node type passed in to ProcessPackages was invalid. Cannot continue.");
                        return InstallerReturnValue.InvalidParameter;
                        
                }
            }
            return InstallerReturnValue.Success;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="driversNode"></param>
        /// <returns></returns>
        protected InstallerReturnValue ProcessDrivers(XmlNode driversNode)
        {
            if (driversNode == null)
            {
                WriteLog("driversNode parameter passed in to ProcessDrivers was null. Cannot continue.\n");
                return InstallerReturnValue.InvalidParameter;
            }
            if (driversNode.HasChildNodes == false)
            {
                WriteLog("driversNode parameter passed in had no child nodes. Cannot continue.\n");
                return InstallerReturnValue.InvalidParameter;
            }
            WriteLog("Processing drivers....");
                    
            InstallerReturnValue retval = InstallerReturnValue.Success;

            for (int i = 0; i < driversNode.ChildNodes.Count; i++)
            {
                int percent = Convert.ToInt32(i / driversNode.ChildNodes.Count);
                        
                
                XmlNode node = driversNode.ChildNodes[i];
                if (node.NodeType == XmlNodeType.Comment)
                {
                    WriteLog("This node is a comment. Skipping");
                    continue;
                }

                WriteLog("Processing node " + (i + 1) + " of " + driversNode.ChildNodes.Count);
                string action = IntegrationKitUtilities.GetXmlAttribute(node, "Action");
                WriteLog("Action type: " + action + " " + node.Name);
                        
                switch (node.Name)
                {
                    case "Category":
                        SetStatusMessage(Properties.Resources.Installer_Section_DriverCategories, "", InstallerReturnValue.Success, percent);
                                                
                        if (ProcessDriverCategory(node, action) != InstallerReturnValue.Success)
                        {
                            WriteLog("ProcessDriverCategory returned an error. Cannot continue.\n");
                            return InstallerReturnValue.Error;
                        }
                        break;

                    case "Driver":
                        SetStatusMessage(Properties.Resources.Installer_Section_Drivers, "", InstallerReturnValue.Success, percent);
                        
                        if (ProcessDriver(node, action) != InstallerReturnValue.Success)
                        {
                            WriteLog("ProcessDriver returned an error. Cannot continue.");
                            return InstallerReturnValue.Error;
                        }
                        break;

                    case "DriverPackage":
                        SetStatusMessage(Properties.Resources.Installer_Section_DriverPackages, "", InstallerReturnValue.Success, percent);
                        
                        if (ProcessDriverPackage(node, action) != InstallerReturnValue.Success)
                        {
                            WriteLog("ProcessDriverPackage returned an error. Cannot continue.");
                            return InstallerReturnValue.Error;
                        }
                        break;

                    default:
                        WriteLog("Error. ProcessDriverPackage encountered an invalid node name : " + node.Name);
                        return InstallerReturnValue.Error;
                }
                if (retval != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }
            }
            return InstallerReturnValue.Success;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="actionsNode"></param>
        /// <returns></returns>
        protected InstallerReturnValue ProcessCustomActions(XmlNode actionsNode)
        {
            WriteLog(Properties.Resources.Installer_Section_CustomActions);

            if (actionsNode == null)
            {
                WriteLog("actionsNode parameter passed in to ProcessCustomActions was null. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            //if (Connection == null)
            //{
            //    WriteLog("Connection to SCCM server is not valid. Cannot continue.");
            //    return InstallerReturnValue.ConnectionInvalid;
            //}
            if (actionsNode.HasChildNodes == false)
            {
                WriteLog("actionsNode parameter passed in had no child nodes. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }

            for (int i = 0; i < actionsNode.ChildNodes.Count; i++)
            {
                WriteLog("Processing custom action " + (i + 1) + " of " + actionsNode.ChildNodes.Count);

                if (actionsNode.ChildNodes[i].NodeType == XmlNodeType.Comment)
                {
                    WriteLog("XML node was commented out - skipping.");
                }
                else
                {
                    string action = IntegrationKitUtilities.GetXmlAttribute(actionsNode.ChildNodes[i], "Action");

                    if (ProcessCustomAction(actionsNode.ChildNodes[i], action) != InstallerReturnValue.Success)
                    {
                        WriteLog("ProcessCustomAction returned an error. Cannot continue.");
                        return InstallerReturnValue.Error;
                    }
                }
            }
            return InstallerReturnValue.Success;
        }



        #endregion

        #region Processing of XML sub-sections

        //===[ begin modification ]======================================
        // Modified 9/24/08 by rhearn
        // - Added code to process changes to UpdateDialogsHelpInfo.xml

        /// <summary>
        ///     
        /// </summary>
        /// <param name="helpUpdates" type="System.Xml.XmlNodeList">
        ///     <para>
        ///         
        ///     </para>
        /// </param>
        /// <returns>
        ///     A Microsoft.ConfigurationManagement.IntegrationDevelopmentKit.SccmObjectInstaller.InstallerReturnValue value...
        /// </returns>
        private InstallerReturnValue UpdateDialogsHelpInfo(XmlNodeList helpUpdates)
        {
            try
            {
                WriteLog(Properties.Resources.Installer_Section_MOF);

                if ((helpUpdates == null) || (helpUpdates.Count == 0))
                {
                    WriteLog("helpUpdates parameter passed in to UpdateDialogsHelpInfo was null. Cannot continue.");
                    return InstallerReturnValue.InvalidParameter;
                }


                WriteLog("Found " + helpUpdates.Count + " changes to process.");
                for (int i = 0; i < helpUpdates.Count; i++)
                {
                    WriteLog("Now processing update " + (i + 1) + " of " + helpUpdates.Count);

                    string className = IntegrationKitUtilities.GetXmlAttribute(helpUpdates[i], "ClassName");
                    string helpId = IntegrationKitUtilities.GetXmlAttribute(helpUpdates[i], "HelpId");
                    string action = IntegrationKitUtilities.GetXmlAttribute(helpUpdates[i], "Action");

                    if (string.IsNullOrEmpty(className))
                    {
                        WriteLog("ClassName parameter in XML was null. Cannot continue.");
                        return InstallerReturnValue.InvalidParameter;
                    }

                    if (string.IsNullOrEmpty(helpId))
                    {
                        WriteLog("HelpId parameter in XML was null. Cannot continue.");
                        return InstallerReturnValue.InvalidParameter;
                    }

                    if (string.IsNullOrEmpty(action))
                    {
                        WriteLog("Action parameter in XML was null. Cannot continue.");
                        return InstallerReturnValue.InvalidParameter;
                    }

                    WriteLog("Action to perform: " + action);
                    string adminUiDir = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Setup", "UI Installation Directory");
                    if (string.IsNullOrEmpty(adminUiDir))
                    {
                        //WriteLog("AdminUILocalInstallDir property value was not found in the registry. Trying ConfigMgrLocalInstallDir ");
                        adminUiDir = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Installation Directory");

                        if (string.IsNullOrEmpty(adminUiDir))
                        {
                            WriteLog("Error! Admin UI directory was not found in the registry.");
                            return InstallerReturnValue.Error;
                        }
                        else
                        {
                            //rhearn: 120308 : fixed bug #3335 by removing trailing backslash on next line 
                            adminUiDir += "\\AdminUI";
                        }
                    }
                                        
                    string helpInfoFile = adminUiDir + "\\XmlStorage\\Other\\dialogshelpinfo.xml";

                    if (File.Exists(helpInfoFile) == false)
                    {
                        WriteLog("Could not find the dialogshelpinfo.xml file! : " + helpInfoFile);
                        return InstallerReturnValue.Error;
                    }
                    WriteLog("backing up the XML file: " + helpInfoFile);
                    //rhearn: bug 3427 - fixed by adding try/catch
                    try
                    {
                        File.Copy(helpInfoFile, helpInfoFile + ".bak");
                    }
                    catch (Exception e)
                    {
                        WriteLog("ERROR (non-fatal): Exception while backing up the dialogshelpinfo.xml file.\n" + e.StackTrace);
                    }

                    WriteLog("Loading the XML file: " + helpInfoFile);
                    XmlDocument helpInfoXml = new XmlDocument();

                    try
                    {
                        helpInfoXml.Load(helpInfoFile);
                    }
                    catch (Exception e)
                    {
                        WriteLog("ERROR: Could not load the dialogshelpinfo.xml file into an XMLDocument!\n" + e.StackTrace);
                        return InstallerReturnValue.Error;
                    }

                    WriteLog("Action to perform: " + action);


                    if (string.Compare(action, "Create", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        WriteLog("Attempting to create a new element in the XML file");
                        XmlNode currentNode = IntegrationKitUtilities.GetXmlNode(helpInfoXml, "//HelpInfo[DialogID='" + className + "']");
                        if (currentNode != null)
                        {
                            WriteLog("Cannot create a new node - the node for this DialogId already exists. (non-fatal)");
                            return InstallerReturnValue.Success;
                        }
                        currentNode = IntegrationKitUtilities.GetXmlNode(helpInfoXml, "//AllDialogsHelpInfo");
                        if (currentNode == null)
                        {
                            WriteLog("ERROR: Cannot locate the AllDialogsHelpInfo node! Cannot append new node!");
                            return InstallerReturnValue.Error;
                        }
                        //create the XML element
                        XmlElement newHelpInfoElement = helpInfoXml.CreateElement("HelpInfo");
                        XmlElement newDialogIdElement = helpInfoXml.CreateElement("DialogID");
                        XmlElement newHelpIdElement = helpInfoXml.CreateElement("HelpID");
                        newHelpIdElement.InnerText = helpId;
                        newDialogIdElement.InnerText = className;
                        //rhearn: updated 12/4/08 to fix issue where HelpID element was getting placed inside DialogId element
                        //        HelpId and DialogId should be siblings inside HelpInfo
                        //newDialogIdElement.AppendChild(newHelpIdElement);  // the old line
                        newHelpInfoElement.AppendChild(newDialogIdElement);
                        newHelpInfoElement.AppendChild(newHelpIdElement);  //the new line
                        currentNode.AppendChild(newHelpInfoElement);
                        
                        FileStream fs = new FileStream(helpInfoFile, FileMode.Truncate, FileAccess.Write, FileShare.ReadWrite, 8, true);
                        StreamWriter sw = new StreamWriter(fs);
                        sw.Write(helpInfoXml.OuterXml);
                        sw.Close();

                        return InstallerReturnValue.Success;

                    }
                    else if (string.Compare(action, "Delete", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        WriteLog("Attempting to delete an element in the XML file - //HelpInfo[/DialogID='" + className + "']");
                        XmlNode currentNode = IntegrationKitUtilities.GetXmlNode(helpInfoXml, "//HelpInfo[/DialogID='" + className + "']");
                        if (currentNode == null)
                        {
                            WriteLog("Cannot delete the node - the node for this DialogId does not exist. (non-fatal)");
                            return InstallerReturnValue.Success;
                        }

                        XmlNode parentNode = IntegrationKitUtilities.GetXmlNode(helpInfoXml, "//AllDialogsHelpInfo");
                        if (parentNode == null)
                        {
                            WriteLog("ERROR: Cannot locate the AllDialogsHelpInfo node! Cannot delete child node!");
                            return InstallerReturnValue.Error;
                        }
                        //delete the XML element
                        parentNode.RemoveChild(currentNode);

                        FileStream fs = new FileStream(helpInfoFile, FileMode.Truncate, FileAccess.Write, FileShare.ReadWrite, 8, true);
                        StreamWriter sw = new StreamWriter(fs);
                        sw.Write(helpInfoXml.OuterXml);
                        sw.Close();

                        return InstallerReturnValue.Success;
                        
                    }
                    else if (string.Compare(action, "Update", StringComparison.OrdinalIgnoreCase) == 0)
                    {
                        WriteLog("Attempting to modify an existing element in the XML file - //HelpInfo[/DialogID='" + className + "']");
                        XmlNode currentNode = IntegrationKitUtilities.GetXmlNode(helpInfoXml, "//HelpInfo[/DialogID='" + className + "']");
                        if (currentNode != null)
                        {
                            WriteLog("Cannot edit the node - the node for this DialogId does not exist.");
                            return InstallerReturnValue.Error;
                        }
                        
                        //edit the XML element
                        XmlNode helpIdNode = IntegrationKitUtilities.GetXmlNode(currentNode.ParentNode, "/HelpID");
                        helpIdNode.InnerText = helpId;
                        
                        FileStream fs = new FileStream(helpInfoFile, FileMode.Truncate, FileAccess.Write, FileShare.ReadWrite, 8, true);
                        StreamWriter sw = new StreamWriter(fs);
                        sw.Write(helpInfoXml.OuterXml);
                        sw.Close();

                        return InstallerReturnValue.Success;
                        
                    }
                }

                return InstallerReturnValue.Error;
            }
            catch
            {
                WriteLog("Exception occurred in UpdateDialogsHelpInfo ");
                WriteLog(" ");
                return InstallerReturnValue.Error;
            }
        }

        //===[ end modification ]======================================
            
        private InstallerReturnValue ProcessFolder(XmlNode node, string action)
        {
            //WriteLog("Now in ProcessFolder()"); 
            
            if (IntegrationKitUtilities.IsValidXmlElement(node) == false)
            {
                if (node.NodeType == XmlNodeType.Comment)
                {
                    //WriteLog("Node was a comment - skipping.");
                    return InstallerReturnValue.Success;
                }
                WriteLog("node parameter passed in to ProcessFolder was not a valid XML element. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            if (Connection == null)
            {
                WriteLog("Connection to Configuration Manager server is not valid. Cannot continue.");
                return InstallerReturnValue.ConnectionInvalid;
            }
                      
            
            string ID = IntegrationKitUtilities.GetXmlAttribute(node, "ID");
            string folderName = IntegrationKitUtilities.GetXmlNodeValue(node, ".//Name");
            string objectType = IntegrationKitUtilities.GetXmlNodeValue(node, ".//ObjectType");

            string parentFolderName = IntegrationKitUtilities.GetXmlNodeValue(node, ".//ParentFolder");
            string searchString = IntegrationKitUtilities.GetXmlNodeValue(node, ".//SearchString");
            string newParentFolderName = IntegrationKitUtilities.GetXmlNodeValue(node, ".//NewParentFolder");
            
            if (string.IsNullOrEmpty(folderName))
            {
                return InstallerReturnValue.InvalidParameter;
            }

            if (string.IsNullOrEmpty(objectType))
            {
                return InstallerReturnValue.InvalidParameter;
            }

            IntegrationKitUtilities.ContainerItemType containerNodeType;
            try
            {
                containerNodeType = (IntegrationKitUtilities.ContainerItemType)Enum.Parse(typeof(IntegrationKitUtilities.ContainerItemType), objectType, true);
            }
            catch
            {
                WriteLog("Invalid objectType parameter specified during ProcessFolders: " + objectType);
                return InstallerReturnValue.InvalidParameter;
            }
            Nullable<int> parentNodeID = GetParentFolderID(parentFolderName, containerNodeType);
            if (parentNodeID.HasValue == false)
            {
                parentNodeID = 0;
            }

            //WriteLog("ID: " + ID);
            WriteLog("Folder Name: " + folderName + " / Container Type: " + containerNodeType);
            WriteLog("Action to perform: " + action);

            IResultObject folderObject = null;
            if (string.Compare(action, "Create", StringComparison.OrdinalIgnoreCase) == 0)
            {
                //WriteLog("Calling CreateConsoleFolder()");
                folderObject = IntegrationKitUtilities.CreateConsoleFolder(Connection, folderName, containerNodeType, parentNodeID.Value, searchString);
                if (folderObject == null)
                {
                    WriteLog("An error occurred while creating the folder.");
                    return InstallerReturnValue.InvalidParameter;
                }
                folderName = IntegrationKitUtilities.GetROStringProperty(folderObject, "Name");
                int? folderID = IntegrationKitUtilities.GetROIntegerProperty(folderObject, "ContainerNodeID");

                WriteLog("Successfully created the folder: " + folderName + " / ID = " + folderID.Value );
                WriteXmlLog(NodeType.Folder, folderObject, ID);

            }
            else if (string.Compare(action, "Delete", StringComparison.OrdinalIgnoreCase) == 0)
            {
                WriteLog("Finding the folder on the Config Mgr server");

                IResultObject folder = IntegrationKitUtilities.GetFolderByName(connection, folderName, containerNodeType, parentFolderName);
                if (folder == null)
                {
                    WriteLog("Could not locate the folder on the Config Mgr server. No need to delete.");
                    return InstallerReturnValue.Success;
                }
                else
                {
                    int? containerID = IntegrationKitUtilities.GetROIntegerProperty(folder, "ContainerNodeID");
                    if (containerID.HasValue)
                    {
                        WriteLog("Located the folder: " + folderName + " / ID = " + containerID.Value);
                        WriteLog("Attempting to delete the folder.");
                        if (IntegrationKitUtilities.DeleteConsoleFolder(connection, containerID.Value) == false)
                        {
                            WriteLog("Error deleting the folder. Skipping.");
                            return InstallerReturnValue.Success;
                        }
                        WriteLog("Deleted the folder : " + folderName);

                    }
                }
            }
            else if (string.Compare(action, "Update", StringComparison.OrdinalIgnoreCase) == 0)
            {
                //
                //
                //
                //update folder code to go here
                //
                //
                //
            }
            else 
            {
                WriteLog("Invalid XML element name specified in ProcessFolders: " + node.Name);
                return InstallerReturnValue.InvalidParameter;
            }
            return InstallerReturnValue.Success;
        }

        private InstallerReturnValue ProcessSWDPackage(XmlNode packageNode, string action)
        {
            if (IntegrationKitUtilities.IsValidXmlElement(packageNode) == false)
            {
                if (packageNode.NodeType == XmlNodeType.Comment)
                {
                    WriteLog("Node was a comment - skipping.\n");
                    return InstallerReturnValue.Success;
                }
                WriteLog("node parameter passed in to ProcessFolder was not a valid XML element. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            if (Connection == null)
            {
                WriteLog("Connection to SCCM server is not valid. Cannot continue.");
                return InstallerReturnValue.ConnectionInvalid;
            }
                
            string ID = IntegrationKitUtilities.GetXmlAttribute(packageNode, "ID");
            IResultObject newPackage = null;

            string packageName = IntegrationKitUtilities.GetXmlNodeValue(packageNode, ".//Name");
            string packageMfr = IntegrationKitUtilities.GetXmlNodeValue(packageNode, ".//Manufacturer");
            string packageDesc = IntegrationKitUtilities.GetXmlNodeValue(packageNode, ".//Description");
            string packageVersion = IntegrationKitUtilities.GetXmlNodeValue(packageNode, ".//Version");

            XmlNode pathNode = IntegrationKitUtilities.GetXmlNode(packageNode, ".//PkgSourcePath");

            string packageSourcePath = IntegrationKitUtilities.GetXmlNodeValue(packageNode, ".//PkgSourcePath");
            packageSourcePath = ParseRelativePath(packageSourcePath, pathNode);
            if (string.IsNullOrEmpty(packageSourcePath))
            {
                WriteLog("Error! packageSourcePath was null after parsing relative path!");
                return InstallerReturnValue.Error;
            }

            if (string.Compare(action, "Create", StringComparison.OrdinalIgnoreCase) == 0)
            {
                WriteLog("Adding package '" + packageName + "' to Configuration Manager");

                if (Directory.Exists(packageSourcePath) == false)
                {
                    WriteLog("Error: Could not locate the packageSourcePath directory: " + packageSourcePath);
                    return InstallerReturnValue.Error;
                }

                try
                {
                    newPackage = integrationUtils.CreatePackage(connection, packageName, packageDesc, packageSourcePath, packageMfr, packageVersion);
                }
                catch (Exception ex1)
                {
                    newPackage = null;
                    string message = ex1.Message + "\n" + ex1.StackTrace + "\n" + ex1.Data + "\n" + ex1.InnerException;
                    WriteError(message);
                }
                if (newPackage == null)
                {
                    WriteLog("Error! CreatePackage() did not return a valid object.");
                    return InstallerReturnValue.Error;
                }
                WriteLog("Package created successfully.");

                if (ProcessFolderTaskForObject(packageNode, newPackage, IntegrationKitUtilities.ContainerItemType.Package) != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }
                
                //string packageID = IntegrationKitUtilities.GetROStringProperty(newPackage, "PackageID");
                //if (string.IsNullOrEmpty(packageID))
                //{
                //    WriteLog("Error! Package ID returned null from new package\n");
                //    return InstallerReturnValue.Error;
                //}
                //WriteLog("PackageID is " + packageID + "\n");
                                                                
            }
            else if (string.Compare(action, "Delete", StringComparison.OrdinalIgnoreCase) == 0)
            {
                WriteLog("Package to delete: " + packageName);
                
                IResultObject packageObject = IntegrationKitUtilities.GetPackageByName(connection, packageName, IntegrationKitUtilities.PackageType.SWDPackage, packageVersion);
                if (packageObject == null)
                {
                    WriteLog("Could not locate package to delete. Skipping.");
                    return InstallerReturnValue.Success;
                }
                
                string packageID = IntegrationKitUtilities.GetROStringProperty(packageObject, "PackageID");
                if (string.IsNullOrEmpty(packageID))
                {
                    WriteLog("Error! Could not get package ID from the driver package. Skipping.");
                    return InstallerReturnValue.Success;
                }
                WriteLog("Located package to delete. PackageID = " + packageID);
                
                if (integrationUtils.DeletePackage(connection, packageID) == false)
                {
                    WriteLog("Error! DeletePackage() returned an error. Skipping.");
                    return InstallerReturnValue.Success;
                }
                WriteLog("Package deleted successfully.");
                return InstallerReturnValue.Success;
            }
            else if (string.Compare(action, "Update", StringComparison.OrdinalIgnoreCase) == 0)
            {
                //
                //
                //
                //    NOT YET IMPLEMENTED
                //
                //
                //
                //
            }
            else
            {
                WriteLog("Error! Invalid action used in ProcessSWDPackage(): " + action );
                return InstallerReturnValue.InvalidParameter;  
            }

            
            return InstallerReturnValue.Success;
        }

        private InstallerReturnValue AddPackageToFolder(string objectID, XmlNode objectNode, IntegrationKitUtilities.ContainerItemType containerType, XmlNode folderNode)
        {
            if (string.IsNullOrEmpty(objectID))
            {
                WriteLog("Error! Package ID returned null from new package\n");
                return InstallerReturnValue.Error;
            }
            string ID = IntegrationKitUtilities.GetXmlAttribute(objectNode, "ID");
            
            string packageFolderName = string.Empty;
            string packageFolderParentName = string.Empty;
            packageFolderName = IntegrationKitUtilities.GetXmlAttribute(folderNode, "FolderName");
            packageFolderParentName = IntegrationKitUtilities.GetXmlAttribute(folderNode, "ParentContainerNode");
            
            
            if (string.IsNullOrEmpty(packageFolderName))
            {
                WriteLog("Error! folder name in the 'AddToFolder' node was null!\n");
                return InstallerReturnValue.InvalidParameter;
            }

            WriteLog("Adding package to folder '" + packageFolderName + "'");
            WriteLog("Folder parent name : '" + packageFolderParentName + "'");
            
            //WriteLog("objectID is " + objectID);
            IResultObject folderObject = null;
            Nullable<int> folderNodeID = null;
            string folderStringID = GetObjectInstanceIdFromXml(packageFolderName, NodeType.Folder);
            if (string.IsNullOrEmpty(folderStringID))
            {
                //folder not found in this install XML - need to try and find in the DB
                WriteLog("The folder was not installed as part of this installation. Looking for the folder name in the SCCM database.");

                folderObject = IntegrationKitUtilities.GetFolderByName(Connection, packageFolderName, containerType, packageFolderParentName);
                if (folderObject == null)
                {
                    WriteLog("Folder name was not found in Config Manager. The package will be left in the root node.");
                    return InstallerReturnValue.Success;
                }
                else
                {
                    folderNodeID = IntegrationKitUtilities.GetROIntegerProperty(folderObject, "ContainerNodeID");
                    if (folderNodeID.HasValue == false)
                    {
                        WriteLog("An error occurred while parsing the folder node ID. The value was null");
                        return InstallerReturnValue.InvalidParameter;
                    }
                }
            }
            else
            {
                //WriteLog("Found a folder ID in the XML : " + folderStringID);
                int folderID = 0;
                if (int.TryParse(folderStringID, out folderID) == false)
                {
                    WriteLog("An error occurred while parsing the folder node ID: " + folderStringID);
                    return InstallerReturnValue.InvalidParameter;
                }
                else
                {
                    folderNodeID = folderID;
                }
            }
            WriteLog("Now writing the object to folder node ID: " + folderNodeID.Value);

            IResultObject newPackageInFolder = IntegrationKitUtilities.CreateConsoleFolderItem(Connection, objectID, containerType, folderNodeID.Value);
            if (newPackageInFolder == null)
            {
                WriteLog("CreateConsoleFolderItem() returned a null value");
                return InstallerReturnValue.Error;
            }
            WriteLog("Successfully saved the package in the folder.");
            WriteXmlLog(NodeType.Folder, newPackageInFolder, packageFolderName);

            return InstallerReturnValue.Success;

        }

        private InstallerReturnValue ProcessDriver(XmlNode driverNode, string action)
        {
            if (driverNode == null)
            {
                WriteLog("driverNode parameter passed in to ProcessDriver was null. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            if (driverNode.HasChildNodes == false)
            {
                WriteLog("driverNode parameter passed in had no child nodes. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            if (string.IsNullOrEmpty(action))
            {
                WriteLog("action parameter passed in was null. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }

            string ID = IntegrationKitUtilities.GetXmlAttribute(driverNode, "ID");
            XmlNode pathNode = IntegrationKitUtilities.GetXmlNode(driverNode, "./DriverPath");
            string driverPath = IntegrationKitUtilities.GetXmlNodeValue(driverNode, "./DriverPath");
            driverPath = ParseRelativePath(driverPath, pathNode);
            string infFile = string.Empty;
            //===[ begin modification ]==================================
            // Modified 9/16/08 by rhearn
            // - added a new string to hold driver name as specified in the XML
            string driverName = string.Empty;
            
            //===[ end modification ]==================================
            
            IResultObject driver = null;
            IResultObject newDriver = null;

            
            if (driverPath.StartsWith("\\") == false)
            {
                WriteLog("Error! Driver path must be in UNC format. Local directories are not permitted");
                return InstallerReturnValue.Error;
            }
            

            if (string.Compare(action.Substring(0, 6), "Create", StringComparison.OrdinalIgnoreCase) == 0)
            {
                WriteLog("Creating the driver.");
                    
                if (string.Compare(action, "CreateFromInf", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    infFile = IntegrationKitUtilities.GetXmlNodeValue(driverNode, "INFFile");
                    if (string.IsNullOrEmpty(infFile))
                    {
                        WriteLog("ERROR: INF file name was blank in XML!");
                        return InstallerReturnValue.InvalidParameter;
                    }

                    //===[ begin modification ]==================================
                    // Modified 9/16/08 by rhearn
                    // - added a new string to hold driver name as specified in the XML
                    driverName = IntegrationKitUtilities.GetXmlNodeValue(driverNode, "DriverName");
                    //===[ end modification ]==================================
            
                    WriteLog("Importing a driver (INF) via : " + infFile);
                    WriteLog("Path to file: " + driverPath);
                    if (File.Exists(driverPath + Path.DirectorySeparatorChar + infFile) == false)
                    {
                        WriteLog("ERROR: INF file does not exist: " + driverPath + Path.DirectorySeparatorChar + infFile);
                        return InstallerReturnValue.InvalidParameter;
                    }
                    driver = IntegrationKitUtilities.ImportInfDriver(Connection, driverPath, infFile, driverName);
                }
                else if (string.Compare(action, "CreateFromOem", StringComparison.OrdinalIgnoreCase) == 0)
                {
                   
                    infFile = IntegrationKitUtilities.GetXmlNodeValue(driverNode, "OEMFile");
                    if (string.IsNullOrEmpty(infFile))
                    {
                        WriteLog("ERROR: OEM file name was blank in XML!");
                        return InstallerReturnValue.InvalidParameter;
                    }

                    //===[ begin modification ]==================================
                    // Modified 9/16/08 by rhearn
                    // - added a new string to hold driver name as specified in the XML
                    driverName = IntegrationKitUtilities.GetXmlNodeValue(driverNode, "DriverName");
                    //===[ end modification ]==================================
            
                    WriteLog("Importing a driver (OEM) via : " + infFile);
                    WriteLog("Path to file: " + driverPath);
                    if (File.Exists(driverPath + Path.DirectorySeparatorChar + infFile) == false)
                    {
                        WriteLog("ERROR: OEM file does not exist: " + driverPath + Path.DirectorySeparatorChar + infFile);
                        return InstallerReturnValue.InvalidParameter;
                    }
                    driver = IntegrationKitUtilities.ImportOemDriver(Connection, driverPath, infFile, driverName);
                    
                }
                
                if (driver == null)
                {
                    WriteLog("Import Driver returned a null value!");
                    return InstallerReturnValue.Error;
                }
                driverName = IntegrationKitUtilities.GetROStringProperty(driver, "LocalizedDisplayName");
                WriteLog("Driver successfully imported : " + driverName);
                
                WriteXmlLog(NodeType.Driver, driver, ID);

                newDriver = driver;

                //
                // ADD TO CATEGORIES
                //
                if (ProcessCategoryTaskForDriver(driverNode, newDriver) != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }

                //
                // ADD TO DRIVER PACKAGES
                //
                if (ProcessDriverPackageTasksForDriver(driverNode, newDriver) != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }

                //
                // ADD TO FOLDER
                //
                if (ProcessFolderTaskForObject(driverNode, newDriver, IntegrationKitUtilities.ContainerItemType.Driver) != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }

                //
                // ADD TO BOOT IMAGES
                //
                if (ProcessBootImageTasksForDriver(driverNode, newDriver) != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }

            }
            else if (string.Compare(action, "Update", StringComparison.OrdinalIgnoreCase) == 0)
            {
                //
                //
                //
                //    NOT YET IMPLEMENTED
                //
                //
                //
                //
            }
            else if (string.Compare(action, "Delete", StringComparison.OrdinalIgnoreCase) == 0)
            {
                WriteLog("Removing the driver.");
                
                infFile = IntegrationKitUtilities.GetXmlNodeValue(driverNode, "INFFile");
                if (string.IsNullOrEmpty(infFile))
                {
                    WriteLog("INFFile was null. Trying OEMFile");
                    infFile = IntegrationKitUtilities.GetXmlNodeValue(driverNode, "OEMFile");
                }
                if (string.IsNullOrEmpty(infFile))
                {
                    WriteLog("OEMFile was null. Cannot continue");
                    return InstallerReturnValue.Success;
                }

                WriteLog("INFFile/OEMFile value: " + infFile);

                //modified 2/3/09 by rhearn to fix issues where correct matching driver was not getting returned
                FileInfo infFileinfo = new FileInfo(Path.Combine(driverPath, infFile));
                if (infFileinfo == null)
                {
                    WriteLog("Could not get INF file info. Cannot continue");
                    return InstallerReturnValue.Success;
                }

                //IResultObject driverObject = IntegrationKitUtilities.GetDriverByPathAndFile(connection, driverPath, infFile);
                IResultObject driverObject = IntegrationKitUtilities.GetMatchingDriver(connection, infFileinfo);
                if (driverObject == null)
                {
                    WriteLog("Unable to find matching driver. Skipping.");
                    return InstallerReturnValue.Success;
                }
                WriteLog("Matching driver returned to ProcessDriver().");
                    
                
                int? CI_ID = IntegrationKitUtilities.GetROIntegerProperty(driverObject, "CI_ID");
                if (CI_ID.HasValue == false)
                {
                    WriteLog("Unable to find driver CI_ID. Skipping.");
                    return InstallerReturnValue.Success;
                }
                WriteLog("Attempting to delete driver " + CI_ID.Value.ToString());
                if (IntegrationKitUtilities.DeleteDriver(connection, (int)CI_ID.Value) == false)
                {
                    WriteLog("Error while trying to delete the driver. Skipping.");
                    return InstallerReturnValue.Success;
                }
                
                WriteLog("Successfully deleted the driver.");
                return InstallerReturnValue.Success;
            }

           

            return InstallerReturnValue.Success;
        }
        
        private InstallerReturnValue ProcessDriverPackage(XmlNode packageNode, string action)
        {
            if (IntegrationKitUtilities.IsValidXmlElement(packageNode) == false)
            {
                if (packageNode.NodeType == XmlNodeType.Comment)
                {
                    WriteLog("Node was a comment - skipping.\n");
                    return InstallerReturnValue.Success;
                }
                WriteLog("node parameter passed in to ProcessDriverPackage was not a valid XML element. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            if (Connection == null)
            {
                WriteLog("Connection to SCCM server is not valid. Cannot continue.");
                return InstallerReturnValue.ConnectionInvalid;
            }
            try
            {

                string ID = IntegrationKitUtilities.GetXmlAttribute(packageNode, "ID");
                IResultObject newPackage = null;
                string packageName = IntegrationKitUtilities.GetXmlNodeValue(packageNode, ".//Name");
                string packageMfr = IntegrationKitUtilities.GetXmlNodeValue(packageNode, ".//Manufacturer");
                string packageDesc = IntegrationKitUtilities.GetXmlNodeValue(packageNode, ".//Description");
                string packageVersion = IntegrationKitUtilities.GetXmlNodeValue(packageNode, ".//Version");

                WriteLog("Package Name    : " + packageName);
                WriteLog("Package Version : " + packageVersion);

                XmlNode pathNode = IntegrationKitUtilities.GetXmlNode(packageNode, "./PkgSourcePath");

                string packageSourcePath = IntegrationKitUtilities.GetXmlNodeValue(packageNode, ".//PkgSourcePath");
                packageSourcePath = ParseRelativePath(packageSourcePath, pathNode);
                WriteLog("Package Path    : " + packageSourcePath);

                if (string.IsNullOrEmpty(packageSourcePath))
                {
                    WriteLog("Error! packageSourcePath was null after parsing relative path!\n");
                    return InstallerReturnValue.Error;
                }

                if (string.Compare(action, "Create", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    WriteLog("Creating driver package: " + packageName);

                    if (Directory.Exists(packageSourcePath) == false)
                    {
                        if (Directory.CreateDirectory(packageSourcePath) == null)
                        {
                            WriteLog("Error! CreateDriverPackage() could not create the packageSourcepath directory: " + packageSourcePath);
                            return InstallerReturnValue.Error;
                        }
                    }

                    try
                    {
                        newPackage = IntegrationKitUtilities.CreateDriverPackage(Connection, packageName, packageDesc, packageSourcePath, packageMfr, packageVersion);
                    }
                    catch (Exception ex1)
                    {
                        newPackage = null;
                        string message = ex1.Message + "\n" + ex1.StackTrace + "\n" + ex1.Data + "\n" + ex1.InnerException;
                        WriteError(message);
                    }

                    if (newPackage == null)
                    {
                        WriteLog("Error! CreateDriverPackage() did not return a valid object.");
                        return InstallerReturnValue.Error;
                    }
                    WriteLog("Package created successfully.");
                    WriteXmlLog(NodeType.DriverPackage, newPackage, ID);

                    //string packageID = IntegrationKitUtilities.GetROStringProperty(newPackage, "PackageID");
                    //if (string.IsNullOrEmpty(packageID))
                    //{
                    //    WriteLog("Error! Package ID returned null from new package\n");
                    //    return InstallerReturnValue.Error;
                    //}
                    //WriteLog("PackageID is " + packageID + "\n");

                    //
                    //
                    // ADD TO FOLDER
                    //
                    //
                    if (ProcessFolderTaskForObject(packageNode, newPackage, IntegrationKitUtilities.ContainerItemType.DriverPackage) != InstallerReturnValue.Success)
                    {
                        return InstallerReturnValue.Error;
                    }

                }

                else if (string.Compare(action, "Update", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    //
                    //
                    //
                    //    NOT YET IMPLEMENTED
                    //
                    //
                    //
                    //
                }

                else if (string.Compare(action, "Delete", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    WriteLog("Deleting driver package. Name= " + packageName + " - Version: " + packageVersion);
                    
                    IResultObject packageObject = IntegrationKitUtilities.GetPackageByName(connection, packageName, IntegrationKitUtilities.PackageType.DriverPackage, packageVersion);
                    if (packageObject == null)
                    {
                        WriteLog("Could not locate the driver package to delete. Skipping.");
                        return InstallerReturnValue.Success;
                    }
                    WriteLog("GetPackageByName returned a package object.");
                    
                    string packageID = IntegrationKitUtilities.GetROStringProperty(packageObject, "PackageID");
                    if (string.IsNullOrEmpty(packageID))
                    {
                        WriteLog("Error! Could not get package ID from the driver package. Skipping");
                        return InstallerReturnValue.Success;
                    }
                    WriteLog("Package ID to delete: " + packageID);

                    if (IntegrationKitUtilities.DeleteDriverPackage(connection, packageID) == false)
                    {
                        WriteLog("Error! DeleteDriverPackage() returned an error. Skipping");
                        return InstallerReturnValue.Success;
                    }
                    WriteLog("Package deleted successfully.");
                    return InstallerReturnValue.Success;
                }

                else
                {
                    WriteLog("ERROR: Invalid action type used in DriverPackage: " + action);
                    return InstallerReturnValue.Error;
                }


                

                WriteXmlLog(NodeType.DriverPackage, newPackage, ID);
                return InstallerReturnValue.Success;
            }
            catch (Exception ex)
            {
                WriteLog("ERROR: Exception occurred while processing the driver package.\n" + ex.Message );
                return InstallerReturnValue.Error;
            }
        }

        private InstallerReturnValue ProcessDriverCategory(XmlNode driverCategoryNode, string action)
        {
            if (driverCategoryNode == null)
            {
                WriteLog("driverCategoriesNode parameter passed in to ProcessDriverCategories was null. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }

            try
            {
                string ID = IntegrationKitUtilities.GetXmlAttribute(driverCategoryNode, "ID");
                string categoryName = IntegrationKitUtilities.GetXmlAttribute(driverCategoryNode, "CategoryName");

                //WriteLog("ID:" + ID);
                WriteLog("Processing Category Name: " + categoryName);


                if (string.Compare(action, "Create", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    //
                    //  sample category node:
                    //
                    //   <DriverCategory_Create ID="CATEGORY_DELL_SERVER" CategoryName="Dell Server Drivers" />
                    //

                    XmlNode log = IntegrationKitUtilities.GetXmlNode(InstalledComponentsXml, "//InstallationLog");
                    if (log == null)
                    {
                        WriteLog("InstalledComponentsXml not found");
                        return InstallerReturnValue.NoDataFound;
                    }

                    string nodeName = Enum.GetName(typeof(NodeType), NodeType.DriverCategory);
                    XmlElement newElement = InstalledComponentsXml.CreateElement(nodeName);
                    newElement.SetAttribute("ID", ID);
                    XmlElement categoryElement = InstalledComponentsXml.CreateElement("CategoryName");
                    categoryElement.InnerText = categoryName;
                    newElement.AppendChild(categoryElement);
                    log.AppendChild(newElement);

                }
                else if (string.Compare(action, "Delete", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    if (IntegrationKitUtilities.DeleteDriverCategory(connection, categoryName) == false)
                    {
                        WriteLog("Did not successfully delete the category: " + categoryName);
                    }
                    WriteLog("Successfully deleted the category: " + categoryName);
                        
                }
                return InstallerReturnValue.Success;
                
            }
            catch
            {
                WriteLog("ERROR: Exception occurred while processing the driver category");
                return InstallerReturnValue.Error;
            }
        }

        private InstallerReturnValue ProcessCategoryTaskForDriver(XmlNode driverNode, IResultObject driver)
        {
            //WriteLog("Getting a list of categories to add this driver to");

            XmlNodeList categories = IntegrationKitUtilities.GetXmlNodeList(driverNode, "./Category");
            if ((categories == null) || (categories.Count == 0))
            {
                //no categories found
                return InstallerReturnValue.Success;
            }
            WriteLog("A total of " + categories.Count + " categories were listed for this driver.");

            for (int i = 0; i < categories.Count; i++)
            {
                XmlNode categoryNode = categories[i];
                string categoryAction = IntegrationKitUtilities.GetXmlAttribute(categoryNode, "Action");
                if (string.IsNullOrEmpty(categoryAction))
                {
                    categoryAction = "Create";
                }

                string categoryName = IntegrationKitUtilities.GetXmlAttribute(categoryNode, "CategoryName");
                //WriteLog("Attempting to add driver to category (as listed in the XML log): " + categoryName);

                if (string.IsNullOrEmpty(categoryName))
                {
                    WriteLog("ERROR: Category ID listed for the driver was null.");
                    return InstallerReturnValue.InvalidParameter;
                }

                XmlNode installedCategoryNode = LookupObjectFromXmlLog(NodeType.DriverCategory, categoryName);
                if (installedCategoryNode == null)
                {
                    WriteLog("Category ID listed for the driver was not a named category in this XML.");
                    WriteLog("Will try to look up an existing category in Configuration Manager");
                }
                else
                {
                    categoryName = IntegrationKitUtilities.GetXmlNodeValue(installedCategoryNode, "./CategoryName");
                    if (string.IsNullOrEmpty(categoryName))
                    {
                        WriteLog("Category ID listed for the driver was found but could not extract the name. Skipping.");
                        return InstallerReturnValue.Success;
                    }
                }

                if (string.Compare(categoryAction, "Create", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    
                    WriteLog("Attempting to add driver to category (display name) : " + categoryName);

                    driver = IntegrationKitUtilities.AddDriverToCategory(Connection, driver, categoryName);
                    if (driver == null)
                    {
                        WriteLog("Error occurred trying to add the driver to the category.");
                        return InstallerReturnValue.Error;
                    }
                    WriteLog("Successfully added driver to category.");

                }
                else if (string.Compare(categoryAction, "Delete", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    WriteLog("Attempting to delete category: " + categoryName);

                    if (IntegrationKitUtilities.DeleteDriverCategory(connection, categoryName) == false)
                    {
                        WriteLog("Could not delete the category (maybe already deleted?)");
                    }
                    else
                    {
                        WriteLog("Successfully added driver to category.");
                    }
                    return InstallerReturnValue.Success;

                }
                else if (string.Compare(categoryAction, "Update", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    //
                    //
                    //
                    //    NOT YET IMPLEMENTED
                    //
                    //
                    //
                    //
                }
                else
                {
                    WriteLog("Error! Invalid action type specified for Category node under Driver");
                    return InstallerReturnValue.InvalidParameter;
                }
            }//end of FOR loop

            return InstallerReturnValue.Success;
            
        }

        private InstallerReturnValue ProcessDriverPackageTasksForDriver(XmlNode driverNode, IResultObject driver)
        {
            XmlNodeList packages = IntegrationKitUtilities.GetXmlNodeList(driverNode, "./DriverPackage");
            if ((packages == null) || (packages.Count == 0))
            {
                //none to process
                return InstallerReturnValue.Success;
            }
            for (int i = 0; i < packages.Count; i++)
            {
                string packageAction = IntegrationKitUtilities.GetXmlAttribute(packages[i], "Action");
                if (string.IsNullOrEmpty(packageAction))
                {
                    packageAction = "Create";
                }

                string packageXmlName = IntegrationKitUtilities.GetXmlAttribute(packages[i], "PackageID");
                XmlNode packageNode = LookupObjectFromXmlLog(NodeType.DriverPackage, packageXmlName);
                if (packageNode == null)
                {
                    WriteLog("Driver Package Xml Name (ID) listed for the driver was not a named package in this XML. Skipping.");
                    break;
                }
                string packageName = IntegrationKitUtilities.GetXmlNodeValue(packageNode, "./Name");
                if (string.IsNullOrEmpty(packageName))
                {
                    WriteLog("Unabl;e to determine display name of the driver package. Skipping.");
                    break;
                }
                IResultObject driverPackages = IntegrationKitUtilities.GetPackageByName(Connection, packageName, IntegrationKitUtilities.PackageType.DriverPackage, null);
                if (driverPackages == null)
                {
                    WriteLog("GetPackageByName returned null. Driver Package could not be found (not fatal). Skipping this package.");
                    break;
                }
                WriteLog("Driver Package was found.");
                IResultObject driverPackage = null;
                foreach (IResultObject obj in driverPackages)
                {
                    driverPackage = obj;
                    break;
                }
                    
                if (string.Compare(packageAction, "Create", StringComparison.OrdinalIgnoreCase) == 0)
                {

                    WriteLog("Attempting to add driver to driver package : " + packageXmlName);

                    driverPackage = IntegrationKitUtilities.AddDriverToDriverPackage(Connection, driver, driverPackage);
                    if (driverPackage == null)
                    {
                        WriteLog("Error occurred trying to add the driver to the driver package.");
                        return InstallerReturnValue.Error;
                    }
                    WriteLog("Added driver to package. ");
                    WriteXmlLog(NodeType.DriverPackage, driverPackage, packageXmlName);

                }
                else if (string.Compare(packageAction, "Delete", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    WriteLog("Attempting to delete driver from driver package : " + packageXmlName);
                    if (IntegrationKitUtilities.DeleteDriverFromDriverPackage(connection, driver, driverPackage) == false)
                    {
                        WriteLog("Could not successfully remove driver from package. Skipping.");
                    }
                    else
                    {
                        WriteLog("Removed driver from package. ");
                    }
                    return InstallerReturnValue.Success;
                    
                }
                else if (string.Compare(packageAction, "Update", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    //
                    //
                    //
                    //    NOT YET IMPLEMENTED
                    //
                    //
                    //
                    //
                }
                else
                {
                    WriteLog("Error! Invalid action type specified for DriverPackage node under Driver");
                    return InstallerReturnValue.InvalidParameter;
                }
            }
            return InstallerReturnValue.Success;
        }

        private InstallerReturnValue ProcessBootImageTasksForDriver(XmlNode driverNode, IResultObject driver)
        {
            XmlNodeList packages = IntegrationKitUtilities.GetXmlNodeList(driverNode, "./BootImage");
            if ((packages == null) || (packages.Count == 0))
            {
                //none to process
                return InstallerReturnValue.Success;
            }
            for (int i = 0; i < packages.Count; i++)
            {
                string packageAction = IntegrationKitUtilities.GetXmlAttribute(packages[i], "Action");
                if (string.IsNullOrEmpty(packageAction))
                {
                    packageAction = "Create";
                }

                string packageName = string.Empty;
                string packageXmlName = IntegrationKitUtilities.GetXmlAttribute(packages[i], "BootImageID");
                WriteLog("Attempting to add driver to boot image package : " + packageXmlName);

                if (string.IsNullOrEmpty(packageXmlName))
                {
                    WriteLog("ERROR: Package name in XML (BootImageID) was empty!");
                    break;
                }
                XmlNode packageNode = LookupObjectFromXmlLog(NodeType.BootImagePackage, packageXmlName);
                if (packageNode == null)
                {
                    WriteLog("Boot Image Package Xml Name (ID) listed for the driver was not a named package in this XML.");
                    WriteLog("Will try to find an existing boot image package in Configuration Manager");
                    packageName = packageXmlName;
                }
                else
                {
                    packageName = IntegrationKitUtilities.GetXmlNodeValue(packageNode, "./Name");
                    if (string.IsNullOrEmpty(packageName))
                    {
                        WriteLog("Unable to determine display name of the boot image package. Skipping.");
                        break;
                    }
                }
                IResultObject bootImagePackages = IntegrationKitUtilities.GetPackageByName(Connection, packageName, IntegrationKitUtilities.PackageType.BootImagePackage, null);
                if (bootImagePackages == null)
                {
                    WriteLog("GetPackageByName returned null. Boot Image Package could not be found (not fatal). Skipping this package.");
                    break;
                }
                WriteLog("Boot Image Package was found.\n");
                IResultObject bootImagePackage = null;
                foreach (IResultObject obj in bootImagePackages)
                {
                    bootImagePackage = obj;
                    break;
                }
                int driverID = (int)IntegrationKitUtilities.GetROIntegerProperty(driver, "CI_ID");
                string bootimageID = IntegrationKitUtilities.GetROStringProperty(bootImagePackage, "PackageID");


                if (string.Compare(packageAction, "Create", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    //modified 8/14/09 by rhearn
                    // - Added ability to specify a required WinPE version for the driver. 
                    //   If not specified, tries to install regardless of the WinPE version.

                    
                    bootImagePackage = IntegrationKitUtilities.AddDriverToBootImagePackage(Connection, driverID, bootimageID);
                    if (bootImagePackage == null)
                    {
                        WriteLog("Error occurred trying to add the driver to the boot image package.");
                        return InstallerReturnValue.Error;
                    }
                    WriteLog("Added driver to boot image package. ");
                    WriteXmlLog(NodeType.BootImagePackage, bootImagePackage, packageXmlName);

                }
                else if (string.Compare(packageAction, "Delete", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    if (IntegrationKitUtilities.DeleteDriverFromBootImagePackage(connection, driverID, bootimageID) == false)
                    {
                        WriteLog("Unable to remove driver from boot image package. Skipping.");
                    }
                    else
                    {
                        WriteLog("Removed driver from boot image package. ");
                    }
                    return InstallerReturnValue.Success;
                }
                else if (string.Compare(packageAction, "Update", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    //
                    //
                    //
                    //    NOT YET IMPLEMENTED
                    //
                    //
                    //
                    //
                }
                else
                {
                    WriteLog("Error! Invalid action type specified for Boot Image Package node under Driver");
                    return InstallerReturnValue.InvalidParameter;
                }
            }            
            return InstallerReturnValue.Success;
        }
        
        private InstallerReturnValue ProcessFolderTaskForObject(XmlNode packageNode, IResultObject packageObject, IntegrationKitUtilities.ContainerItemType itemType)
        {
            XmlNode folderNode = IntegrationKitUtilities.GetXmlNode(packageNode, "./Folder");
            string ID = string.Empty;
            if (folderNode != null)
            {
                
                //InstallerReturnValue retVal = InstallerReturnValue.Success;
                ID = IntegrationKitUtilities.GetXmlAttribute(packageNode, "ID");

                string packageID = IntegrationKitUtilities.GetObjectInstanceID(packageObject, itemType);
                string folderAction = IntegrationKitUtilities.GetXmlAttribute(folderNode, "Action");
                
                
                if (string.Compare(folderAction, "Create", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    WriteLog("Now adding the object (type : " + itemType + ") to a folder.");
                    if (AddPackageToFolder(packageID, packageNode, itemType, folderNode) != InstallerReturnValue.Success)
                    {
                        return InstallerReturnValue.Error;
                    }
                }
                else if (string.Compare(folderAction, "Delete", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    //
                    //
                    //
                    //    NOT YET IMPLEMENTED
                    //
                    //
                    //
                    //
                }
                else if (string.Compare(folderAction, "Update", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    //
                    //
                    //
                    //    NOT YET IMPLEMENTED
                    //
                    //
                    //
                    //
                }
                else
                {
                    WriteLog("Error! Invalid action type specified for Folder under SWDPackage : " + folderAction);
                    return InstallerReturnValue.Error;
                }
            }
            else
            {
                WriteLog("No folder was specified for this package. It will be placed in the root.");
                WriteXmlLog(NodeType.Package, packageObject, ID);
            }
            return InstallerReturnValue.Success;
        }

        private InstallerReturnValue ProcessBootImagePackage(XmlNode bootImageNode, string action)
        {
            if (IntegrationKitUtilities.IsValidXmlElement(bootImageNode) == false)
            {
                if (bootImageNode.NodeType == XmlNodeType.Comment)
                {
                    WriteLog("Node was a comment - skipping.\n");
                    return InstallerReturnValue.Success;
                }
                WriteLog("node parameter passed in to ProcessBootImagePackage was not a valid XML element. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            if (Connection == null)
            {
                WriteLog("Connection to SCCM server is not valid. Cannot continue.");
                return InstallerReturnValue.ConnectionInvalid;
            }

            //
            //
            //  Need code in here for detecting previously installed boot images and updating them.
            //
            //
            //
            string ID = IntegrationKitUtilities.GetXmlAttribute(bootImageNode, "ID");
            string packageName = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Name");
            string packageDesc = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Description");
            string architecture = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Architecture");
            if (string.Compare(architecture, "x64", StringComparison.OrdinalIgnoreCase) == 0)
            {
                architecture = "amd64";
            }
            else if (IsWaikArchStringValid(architecture) == false)
            {
                architecture = "x86";
            }
            
            string index = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//ImageIndex");
            int imageIndex = 0;
            if (int.TryParse(index, out imageIndex) == false)
            {
                imageIndex = 1;
            }

            WriteLog("Boot image package:     " + packageName);
            WriteLog("Boot image architecture:" + architecture);
            WriteLog("Boot image index number:" + imageIndex);
            
            WriteLog("Action to perform:" + action);
                
            //================[ CREATE FROM WAIK ]=========================

            if (string.Compare(action, "CreateFromWaik", StringComparison.OrdinalIgnoreCase) == 0)
            {
                
                if (CreateBootWim(bootImageNode, GetWaikBootWim(architecture)) != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }
                WriteLog("ProcessBootImagePackages: CreateBootWimFromWaik completed successfully.");
                return InstallerReturnValue.Success;
            }


            //================[ CREATE FROM EXISTING SCCM WIM ]=========================


            else if (string.Compare(action, "CreateFromExistingWim", StringComparison.OrdinalIgnoreCase) == 0)
            {
                if (CreateBootWim(bootImageNode, GetExistingBootWim(bootImageNode)) != InstallerReturnValue.Success)
                {
                    return InstallerReturnValue.Error;
                }
                WriteLog("ProcessBootImagePackages: CreateFromExistingWim completed successfully.");
                return InstallerReturnValue.Success;
            }


           
            else if (string.Compare(action, "ExportDefault", StringComparison.OrdinalIgnoreCase) == 0)
            {
                //
                //
                //
                //    NOT YET IMPLEMENTED
                //
                //
                //
                //
            }
            else if (string.Compare(action, "RefreshDPs", StringComparison.OrdinalIgnoreCase) == 0)
            {
                //
                //
                //
                //    NOT YET IMPLEMENTED
                //
                //
                //
                //
            }
            else if (string.Compare(action, "Delete", StringComparison.OrdinalIgnoreCase) == 0)
            {
                WriteLog("Deleting boot images not yet implemented. Skipping.");
            
                //
                //
                //
                //    NOT YET IMPLEMENTED
                //
                //
                //
                //
            }
            else if (string.Compare(action, "Update", StringComparison.OrdinalIgnoreCase) == 0)
            {
                //
                //
                //
                //    NOT YET IMPLEMENTED
                //
                //
                //
                //
            }
            else
            {
                WriteLog("node element passed to ProcessBootImagePackages was invalid. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            return InstallerReturnValue.Success;
        }

        #endregion

        #region WIM File modifications

        /// <summary>
        /// Ensures that the proper WAIK tools are used to create boot images and prevents 64-bit tools
        /// from being used on a 32-bit OS.
        /// </summary>
        /// <param name="imageArchitecture">The intended architecture type of the image.</param>
        /// <returns>A string containing the correct architecture type to use in the path to the WAIK tools.</returns>
        private string GetWaikToolsArchitecture(string imageArchitecture)
        {
            if (IsWaikArchStringValid(imageArchitecture) == false)
            {
                WriteLog("GetWaikToolsArchitecture: archType parameter (" + imageArchitecture + ") was invalid.");
                return null;
            }
            string cpuArchitecture = IntegrationKitUtilities.GetCPUArchitecture();
            
            if ((string.Compare(cpuArchitecture, "amd64", StringComparison.OrdinalIgnoreCase) == 0) &&
                (string.Compare(imageArchitecture, "amd64", StringComparison.OrdinalIgnoreCase) == 0))
            {
                return "amd64";
            }
            if ((string.Compare(cpuArchitecture, "ia64", StringComparison.OrdinalIgnoreCase) == 0) &&
                (string.Compare(imageArchitecture, "ia64", StringComparison.OrdinalIgnoreCase) == 0))
            {
                return "amd64";
            }
            
            return "x86";


        }

        /// <summary>
        /// Locates the winpe.wim file for the specified architecture within the WAIK directory structure.
        /// </summary>
        /// <param name="archType">The CPU architecture type of the image to locate ("x86", "amd64" or "ia64").</param>
        /// <returns>A Fileinfo object for the winpe.wim file found, or null on any error.</returns>
        private FileInfo GetWaikBootWim(string archType)
        {
            if (IsWaikArchStringValid(archType) == false)
            {
                WriteLog("GetWaikBootWim: archType parameter (" + archType + " was invalid.");
                return null;
            }
            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("GetWaikBootWim: Could not find path to WAIK.");
                return null;
            }
            string wimPath = Path.Combine(waikPath, "Tools" + Path.DirectorySeparatorChar + "PETools" + Path.DirectorySeparatorChar + archType + Path.DirectorySeparatorChar + "winpe.wim");
            FileInfo wimFile = new FileInfo(wimPath);
            if ((File.Exists(wimPath) == false) || (wimFile == null))
            {
                WriteLog("GetWaikBootWim: Could not get file info for the winpe.wim file ( " + wimPath + ")");
                return null;
            }
            WriteLog("GetWaikBootWim: Found the winpe.wim file ( " + wimFile.FullName + ")");
            return wimFile;

        }

        /// <summary>
        /// Locates a boot image from a specified path, confirms the correct architecture and returns a Fileinfo object.
        /// </summary>
        /// <param name="bootImageNode">The node from the installer XML specifying the boot image properties</param>
        /// <returns>A FileInfo object containing the boot wim information</returns>
        private FileInfo GetExistingBootWim(XmlNode bootImageNode)
        {
            

            //get the path to the existing source WIM file from the installer XML
            string existingImage = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//PkgSourcePath");
            XmlNode existingImagePathNode = IntegrationKitUtilities.GetXmlNode(bootImageNode, ".//PkgSourcePath");
            existingImage = ParseRelativePath(existingImage, existingImagePathNode);
            if (string.IsNullOrEmpty(existingImage))
            {
                WriteLog("ProcessBootImagePackages: Error! existingImage was null after parsing relative path!\n");
                return null;
            }
            WriteLog("ProcessBootImagePackages: Path to boot image being copied: " + existingImage);
            FileInfo wimFile = new FileInfo(existingImage);
            if (wimFile == null)
            {
                WriteLog("ProcessBootImagePackages: Error! Existing WIM image does not exist : " + existingImage);
                return null;
            }

            string architecture = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Architecture");
            if (string.Compare(architecture, "x64", StringComparison.OrdinalIgnoreCase) == 0)
            {
                architecture = "amd64";
            }
            else if (IsWaikArchStringValid(architecture) == false)
            {
                // Backward comnpatibility: 
                // Just in case the installer XML was not updated to include the new element "Architecture",
                // the path to the WIM file fill be parsed to see if it's something other than "x86"

                if (existingImage.Contains("x64"))
                {
                    architecture = "amd64";
                }
                else
                {
                    architecture = "x86";
                }
            }
            string index = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//ImageIndex");
            int imageIndex = 0;
            if (int.TryParse(index, out imageIndex) == false)
            {
                imageIndex = 1;
            }

            if (string.Compare(architecture, GetWimArchitecture(wimFile.FullName, imageIndex), StringComparison.OrdinalIgnoreCase) != 0)
            {
                WriteLog("ProcessBootImagePackages: Error! Existing WIM image not the same CPU architecture as target WIM : " + architecture);
                return null;
            }
            return wimFile;
        }

        /// <summary>
        /// Creates (and updates) a new WinPE WIM file by copying an existing WIM file and modifying it.
        /// </summary>
        /// <param name="bootImageNode">An XML node containing the installer directives</param>
        /// <param name="sourceWim">A FileInfo object pointing to the existing WIM file that is the source of the new WIM.</param>
        /// <returns>A return code indicating success or failure.</returns>
        private InstallerReturnValue CreateBootWim(XmlNode bootImageNode, FileInfo sourceWim)
        {
            if (IntegrationKitUtilities.IsValidXmlElement(bootImageNode) == false)
            {
                if (bootImageNode.NodeType == XmlNodeType.Comment)
                {
                    WriteLog("Node was a comment - skipping.\n");
                    return InstallerReturnValue.Success;
                }
                WriteLog("CreateBootWim: node parameter passed in to ProcessBootImagePackage was not a valid XML element. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }

            if (sourceWim == null)
            {
                WriteLog("CreateBootWim: Source WIM file parameter was invalid.)");
                return InstallerReturnValue.InvalidParameter;
            }
            WriteLog("CreateBootWim: Source WIM file : " + sourceWim.FullName);

            if (Connection == null)
            {
                WriteLog("Connection to SCCM server is not valid. Cannot continue.");
                return InstallerReturnValue.ConnectionInvalid;
            }

            
            // Get the path to the WAIK utilities
            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("CreateBootWim: Error! Could not get the path to the WAIK utilities.");
                return InstallerReturnValue.Error;
            }
            WriteLog("CreateBootWim: path to WAIK: " + waikPath);


            //Find the Config Mgr installation directory
            string configMgrDirectory = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Installation Directory");
            string configMgrUNC = @"\\" + serverName + @"\" + "SMS_" + siteCode;
            
            //Get the boot image information from the installer XML
            string packageVersion = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Version");
            string architecture = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Architecture");
            if (string.Compare(architecture, "x64", StringComparison.OrdinalIgnoreCase) == 0)
            {
                //this conversion placed here to offer backward compatibility for anyone who
                //used "x64" in previous releases
                architecture = "amd64";
            } 
            else if (IsWaikArchStringValid(architecture) == false)
            {
                architecture = "x86";
            }
            string index = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//ImageIndex");
            int imageIndex = 0;
            if (int.TryParse(index, out imageIndex) == false)
            {
                imageIndex = 1;
            }

            string newWimPath = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//ImageImportPath");
            XmlNode pathNode = IntegrationKitUtilities.GetXmlNode(bootImageNode, ".//ImageImportPath");
            newWimPath = ParseRelativePath(newWimPath, pathNode);
            if (string.IsNullOrEmpty(newWimPath))
            {
                WriteLog("CreateBootWim: Error! newWimPath was null after parsing relative path!\n");
                return InstallerReturnValue.Error;
            }
            if (newWimPath.StartsWith(configMgrUNC, StringComparison.OrdinalIgnoreCase))
            {
                WriteLog("CreateBootWim: Converting the UNC path to a local path");
                newWimPath = newWimPath.Replace(configMgrUNC, configMgrDirectory);
            }
            WriteLog("CreateBootWim: Path to new WIM file after copy: " + newWimPath);
            
            //extract the parent directory and the filename of the new WIM file
            int pos = newWimPath.LastIndexOf("\\");
            string wimParentDir = newWimPath.Substring(0, pos);
            string wimFileName = newWimPath.Substring(pos + 1);

            //try to create the directory if it doesn't exist
            if (Directory.Exists(wimParentDir) == false)
            {
                try
                {
                    DirectoryInfo wimDir = Directory.CreateDirectory(wimParentDir);
                }
                catch (Exception ex)
                {
                    WriteLog("CreateBootWim: Exception occurred while creating the directory for the WIM file." + ex.StackTrace);
                    return InstallerReturnValue.Error;
                }
            }

            //if the target WIM file already exists, it needs to be renamed.
            if (File.Exists(newWimPath) && (MoveOldWimFile(newWimPath, newWimPath + ".old") != InstallerReturnValue.Success))
            {
                WriteLog("CreateBootWim: An error occurred while renaming the old WIM file: " + newWimPath);
                return InstallerReturnValue.Error;
            }


            // Now that the setup is done, now starts the process of building the new WIM file
            string tempWimPath = Path.Combine(wimParentDir,  "temp.wim");


            // Copy the source image to the new WIM path, creating the target WIM file
            // If the "temp.wim" file aready exists (didn't get cleaned up previously), then remove it
            if (File.Exists(tempWimPath) && (DeleteWimFile(tempWimPath) != InstallerReturnValue.Success))
            {
                WriteLog("CreateBootWim: An error occurred while deleting the old temp.wim file: " + tempWimPath);
                return InstallerReturnValue.Error;
            }


            FileInfo tempWimFile;
            try
            {
                WriteLog("CreateBootWim: Copying WAIK boot.wim to new file.");
                WriteLog("CreateBootWim: Source: " + sourceWim.FullName);
                WriteLog("CreateBootWim: Dest  : " + tempWimPath);
                tempWimFile = sourceWim.CopyTo(tempWimPath, true);
                if (tempWimFile == null)
                {
                    WriteLog("CreateBootWim: Error! Could not copy the WIM file.");
                    return InstallerReturnValue.Error;
                }
                WriteLog("CreateBootWim: WIM file copied successfully to " + tempWimFile.FullName);
            }
            catch (Exception ex)
            {
                WriteLog("CreateBootWim: Exception occurred while copying the WIM file.\n\n" + ex.Message + "\n" + ex.StackTrace + "\n" + ex.InnerException + "\n" + ex.Data);
                return InstallerReturnValue.Error;
            }
            // There is now a temporary boot WIM file to work on.
            string mountPath = Path.Combine(tempWimFile.DirectoryName, "temp");
            WriteLog("CreateBootWim: Mount path : " + mountPath);

            // get the %WINDOWS% directory from the XML info in the WIM file (need to do this before the WIM is mounted)
            string winDir = GetWimSystemRoot(tempWimFile.FullName);
            if (string.IsNullOrEmpty(winDir))
            {
                WriteLog("CreateBootWim: Error! Could not locate system directory from WIM info");
                return InstallerReturnValue.Error;
            }
            string mountPathWinDir = Path.Combine(mountPath, winDir);
            WriteLog("CreateBootWim: Windows system dir in mount path : " + mountPathWinDir);
                        
            // mount the WIM file
            WriteLog("CreateBootWim: Mounting the WIM file: " + tempWimFile.FullName);
            InstallerReturnValue retVal = MountWimFile(tempWimFile.FullName, mountPath, imageIndex);
            if (retVal != 0)
            {
                WriteLog("CreateBootWim: Error [" + retVal + "] occurred while trying to mount the WIM file " + tempWimFile.FullName);
                return InstallerReturnValue.Error;
            }
            
            //now that the WIM is mounted, test the system directory path
            if (Directory.Exists(mountPathWinDir) == false)
            {
                WriteLog("CreateBootWim: Error! Windows system directory (" + mountPathWinDir + ") was not found in mounted image");
                return InstallerReturnValue.Error;
            }
            WriteLog("CreateBootWim: Windows System dir found in mounted image.");

            // Install the packages selected in the installer XML
            XmlNodeList pePackages = IntegrationKitUtilities.GetXmlNodeList(bootImageNode, ".//AddPackage");
            if (pePackages != null)
            {
                WriteLog("CreateBootWim: Adding [" + pePackages.Count + "] packages to WinPE.");
                foreach (XmlNode pePackage in pePackages)
                {
                    string pePackageName = pePackage.InnerText;
                    if (string.IsNullOrEmpty(pePackageName))
                    {
                        WriteLog("CreateBootWim: Error! WinPE package name specified in XML was empty!");
                        return InstallerReturnValue.Error;
                    }
                    WriteLog("CreateBootWim: Adding the " + pePackageName + " package to WinPE.");

                    //modified 9/14/09 by rhearn to fix bug 5580
                    //retVal = InstallPackageToWinPe(tempWimFile.FullName, mountPathWinDir, pePackageName);
                    //modified 11/3/09 by rhearn to fix bug 6134
                    //retVal = InstallPackageToWinPe(tempWimFile.FullName, mountPath, pePackageName);
                    retVal = InstallPackageToWinPe(architecture, mountPath, pePackageName); 
                    if (retVal != 0)
                    {
                        WriteLog("CreateBootWim: Error [" + retVal + "]occurred while trying to install the package into WinPE: " + pePackageName);
                        UnMountWimFile(mountPath, false);
                        return InstallerReturnValue.Error;
                    }
                    WriteLog("CreateBootWim: Package added successfully."); 
                }
            }

            //Change scratch space if specified
            string scratchSpace = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//ScratchSpace");
            if (string.IsNullOrEmpty(scratchSpace) == false)
            {
                WriteLog("CreateBootWim: Updating scratch space in WinPE to this setting: " + scratchSpace);

                //modified 9/14/09 by rhearn to fix bug 5580
                //retVal = ChangeWinPeScratchSpace(mountPathWinDir, scratchSpace, architecture);
                retVal = ChangeWinPeScratchSpace(mountPath, scratchSpace, architecture);
                if (retVal != 0)
                {
                    WriteLog("CreateBootWim: Error [" + retVal + "] occurred while trying to update scratch space in WinPE");
                    UnMountWimFile(mountPath, false); 
                    return InstallerReturnValue.Error;
                }
                WriteLog("CreateBootWim: Scratch space updated successfully.");
            }

            // Prep WinPE (only for WAIK prior to 3.0)

            WriteLog("CreateBootWim: Running 'Prep' on WinPE"); 
            retVal = PrepWinPeImage( mountPath);
            if (retVal != 0)
            {
                WriteLog("CreateBootWim: Error [" + retVal + "] occurred while trying issue a 'prep' command to WinPE");
                UnMountWimFile(mountPath, false); 
                return InstallerReturnValue.Error;
            }

            // Unmount WinPE
            WriteLog("CreateBootWim: Unmounting WinPE Image"); 
            retVal = UnMountWimFile(mountPath, true);
            if (retVal != 0)
            {
                WriteLog("CreateBootWim: Error [" + retVal + "] occurred while trying unmount the WinPE image");
                return InstallerReturnValue.Error;
            }

            // Export WinPE
            WriteLog("CreateBootWim: Exporting WinPE Image"); 
            retVal = ExportWimFile(tempWimPath, newWimPath, imageIndex);
            if (retVal != 0)
            {
                WriteLog("CreateBootWim: Error occurred while trying export WinPE image");
                return InstallerReturnValue.Error;
            }
            
            
            if (File.Exists(newWimPath) == false)
            {
                WriteLog("CreateBootWim: Error! New WIM file does not exist after export: " + newWimPath);
                return InstallerReturnValue.Error;
            }

            

            //revert the path to the WIM file back to a UNC path
            newWimPath = newWimPath.Replace(configMgrDirectory, configMgrUNC);
            
            // Get all other Boot image properties from installer XML
            string ID = IntegrationKitUtilities.GetXmlAttribute(bootImageNode, "ID");
            string packageName = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Name");
            string packageDesc = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Description");
            bool enableLabShell = false;
            string bitmapPath = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//BackgroundBitmapPath");
            string labShell = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//EnableLabShell");
            if (string.IsNullOrEmpty(labShell) == false)
            {
                if (bool.TryParse(labShell, out enableLabShell) == true)
                {
                    enableLabShell = false;
                }
            }
            int pkgSourceFlag = 2;
            int packageType = 258;


            WriteLog("CreateBootWim: Creating a new blank instance of SMS_BootImagePackage"); 
            IResultObject bootImage = IntegrationKitUtilities.CreateNewBootImage(Connection, packageName);
            if (bootImage == null)
            {
                WriteLog("CreateBootWim: ImportBootWim failed to return a valid boot image object. Cannot continue.");
                return InstallerReturnValue.Error;
            }

            // Populate new boot image package properties.
            bootImage["Name"].StringValue = packageName;
            bootImage["Description"].StringValue = packageDesc;
            bootImage["ImagePath"].StringValue = newWimPath; // UNC path required.
            bootImage["ImageIndex"].IntegerValue = imageIndex; // Index into WIM file for image.
            bootImage["PkgSourceFlag"].IntegerValue = pkgSourceFlag; // 
            bootImage["PackageType"].IntegerValue = packageType; // boot image
            bootImage["EnableLabShell"].BooleanValue = enableLabShell;
            bootImage["Version"].StringValue = packageVersion;
            if (string.IsNullOrEmpty(bitmapPath) == false)
            {
                bootImage["BackgroundBitmapPath"].StringValue = bitmapPath;
            }

            WriteLog("CreateBootWim: SMS_BootImagePackage properties:");
            WriteLog("CreateBootWim: Name                 : " + packageName);
            WriteLog("CreateBootWim: Description          : " + packageDesc);
            WriteLog("CreateBootWim: ImagePath            : " + newWimPath);
            WriteLog("CreateBootWim: ImageIndex           : " + imageIndex);
            WriteLog("CreateBootWim: PkgSourceFlag        : " + pkgSourceFlag);
            WriteLog("CreateBootWim: PackageType          : " + packageType);
            WriteLog("CreateBootWim: EnableLabShell       : " + enableLabShell);
            WriteLog("CreateBootWim: BackgroundBitmapPath : " + bitmapPath); 
            


            // Save new package and new package properties.
           // bootImage.AutoCommit = true;
            WriteLog("CreateBootWim: committing the package object using Put()"); 
            bootImage.Put();

            //Cleaning up - removing the temp.wim file
            if (DeleteWimFile(tempWimFile.FullName) != InstallerReturnValue.Success)
            {
                WriteLog("CreateBootWim: An error occurred deleting the temp.wim file. This is not fatal and the install will continue.");
            }


            WriteXmlLog(NodeType.BootImagePackage, bootImage, ID);

            WriteLog("CreateBootWim: Creating any necessary console folder node for the boot image.");
            if (ProcessFolderTaskForObject(bootImageNode, bootImage, IntegrationKitUtilities.ContainerItemType.BootImagePackage) != InstallerReturnValue.Success)
            {
                return InstallerReturnValue.Error;
            }
            WriteLog("CreateBootWim: Completed processing the boot image.");
            return InstallerReturnValue.Success;
        }
     
        /// <summary>
        /// This method has been deprecated. Please use CreateBootWim()
        /// </summary>
        /// <param name="bootImageNode"></param>
        /// <returns></returns>
        private InstallerReturnValue CreateBootWimFromWaik(XmlNode bootImageNode)
        {

            if (IntegrationKitUtilities.IsValidXmlElement(bootImageNode) == false)
            {
                if (bootImageNode.NodeType == XmlNodeType.Comment)
                {
                    WriteLog("Node was a comment - skipping.\n");
                    return InstallerReturnValue.Success;
                }
                WriteLog("node parameter passed in to ProcessBootImagePackage was not a valid XML element. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }

            if (Connection == null)
            {
                WriteLog("Connection to SCCM server is not valid. Cannot continue.");
                return InstallerReturnValue.ConnectionInvalid;
            }

            //=================================================================================
            //
            // modified 8/11/09 by rhearn
            // - The remainder of this method has been commented out. 
            //   Calling this method results in redirection to the new "CreateBootWim" method.
            //
            //=================================================================================
            string architecture = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Architecture");
            if (string.Compare(architecture, "x64", StringComparison.OrdinalIgnoreCase) == 0)
            {
                architecture = "amd64";
            }
            else if (IsWaikArchStringValid(architecture) == false)
            {
                architecture = "x86";
            }

            return CreateBootWim(bootImageNode, GetWaikBootWim(architecture));


           // string configMgrDirectory = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Installation Directory");
           // string configMgrUNC = @"\\" + serverName + @"\" + "SMS_" + siteCode;
            
           // string ID = IntegrationKitUtilities.GetXmlAttribute(bootImageNode, "ID");
           // string packageName = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Name");
           // string packageDesc = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Description");
           // string packageVersion = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Version");

           // string architecture = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Architecture");
           // if (string.IsNullOrEmpty(architecture))
           // {
           //     architecture = "x86";
           // }

           // string existingImage = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//PkgSourcePath");
           // XmlNode existingImagePathNode = IntegrationKitUtilities.GetXmlNode(bootImageNode, ".//PkgSourcePath");
           // existingImage = ParseRelativePath(existingImage, existingImagePathNode);
           // if (string.IsNullOrEmpty(existingImage))
           // {
           //     WriteLog("Error! existingImage was null after parsing relative path!\n");
           //     return InstallerReturnValue.Error;
           // }
           // WriteLog("Path to boot image being copied: " + existingImage);
           // WriteLog("Converting the UNC path to a local path");
           // WriteLog("Path to boot image being copied: " + existingImage);
           // existingImage = existingImage.Replace(configMgrUNC, configMgrDirectory);
            
           // FileInfo fi = new FileInfo(existingImage);
           // if (fi == null)
           // {
           //     WriteLog("Error! Existing WIM image does not exist : " + existingImage);
           //     return InstallerReturnValue.Error;
           // }
           
                        
           // string newWimPath = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//ImageImportPath");
           // XmlNode pathNode = IntegrationKitUtilities.GetXmlNode(bootImageNode, ".//ImageImportPath");
           // newWimPath = ParseRelativePath(newWimPath, pathNode);
           // if (string.IsNullOrEmpty(newWimPath))
           // {
           //     WriteLog("Error! newWimPath was null after parsing relative path!\n");
           //     return InstallerReturnValue.Error;
           // }
           // WriteLog("Path to boot image after export: " + newWimPath);


           // WriteLog("Converting the UNC path to a local path");
           // newWimPath = newWimPath.Replace(configMgrUNC, configMgrDirectory);
           // WriteLog("Path to boot image after export: " + newWimPath);


           // int pos = newWimPath.LastIndexOf("\\");
           // string pathName = newWimPath.Substring(0, pos);
           // string fileName = newWimPath.Substring(pos + 1);
           // if (Directory.Exists(pathName) == false)
           // {
           //     try
           //     {
           //         DirectoryInfo wimDir = Directory.CreateDirectory(pathName);
           //     }
           //     catch (Exception ex)
           //     {
           //         WriteLog("Exception occurred while creating the directory for the WIM file." + ex.StackTrace);
           //         return InstallerReturnValue.Error;
           //     }
           // }

           // if (MoveOldWimFile(newWimPath, newWimPath + ".old") != InstallerReturnValue.Success)
           // {
           //     WriteLog("An error occurred while renaming the old WIM file: " + newWimPath);
           //     return InstallerReturnValue.Error;
           // }

           // // Now that the setup is done, now starts the process of building the new WIM file
           // string tempWimPath = newWimPath + "temp.wim";


           // // Copy the WAIK image to the new WIM path
           // FileInfo tempWimFile;

           // if (MoveOldWimFile(tempWimPath, tempWimPath + ".old") != InstallerReturnValue.Success)
           // {
           //     WriteLog("An error occurred while renaming the old WIM file: " + tempWimPath);
           //     return InstallerReturnValue.Error;
           // }


           // try
           // {
           //     WriteLog("Copying WAIK boot.wim to new file.");
           //     WriteLog("Source: " + fi.FullName);
           //     WriteLog("Dest  : " + tempWimPath);
           //     tempWimFile = fi.CopyTo(tempWimPath);
           //     if (tempWimFile == null)
           //     {
           //         WriteLog("Error! Could not copy the WIM file.");
           //         return InstallerReturnValue.Error;
           //     }
           //     WriteLog("Copied successfully.");
           // }
           // catch (Exception ex)
           // {
           //     WriteLog("Exception occurred while copying the WIM file." + ex.StackTrace + "\n" + ex.InnerException + "\n" + ex.Data);
           //     return InstallerReturnValue.Error;
           // }
            
           // // Get the path to the WAIK utilities for use in the next section.
           // string waikPath = GetWaikPath();
           // if (string.IsNullOrEmpty(waikPath))
           // {
           //     WriteLog("Error! Could not get the path to the WAIK utilities.");
           //     return InstallerReturnValue.Error;
           // }

           // WriteLog("Mounting the WIM file: " + tempWimFile.FullName);
           // string mountPath = Path.Combine(tempWimFile.DirectoryName, "temp");
           // WriteLog("Mount path : " + mountPath);


           // // get the %WINDOWS% directory from the XML info in the WIM file (need to do this before the WIM is mounted)
           // string winDir = GetWimSystemRoot(tempWimFile.FullName);
           // if (string.IsNullOrEmpty(winDir))
           // {
           //     WriteLog("Error! Could not locate system directory from WIM info");
           //     return InstallerReturnValue.Error;
           // }
           // string mountPathWinDir = Path.Combine(mountPath, winDir);
           // WriteLog("System dir in mount path : " + mountPathWinDir);

           // // mount the WIM file
           // InstallerReturnValue retVal;
           // int imageIndex = 1;
           // retVal = MountWimFile(tempWimFile.FullName, mountPath, imageIndex);
           // if (retVal != 0)
           // {
           //     WriteLog("Error occurred while trying to mount the WIM file " + tempWimFile.FullName);
           //     return InstallerReturnValue.Error;
           // }
            
           // //now that the WIM is mounted, test the system directory path
           // if (Directory.Exists(mountPathWinDir) == false)
           // {
           //     WriteLog("Error! System directory was not found in mount path : " + mountPathWinDir);
           //     return InstallerReturnValue.Error;
           // }
           // WriteLog("System dir exists.");

           // // install the packages selected
           // XmlNodeList pePackages = IntegrationKitUtilities.GetXmlNodeList(bootImageNode, ".//AddPackage");
           // if (pePackages != null)
           // {
           //     WriteLog("Adding " + pePackages.Count + " packages to WinPE." );

           //     foreach (XmlNode pePackage in pePackages)
           //     {
           //         string pePackageName = pePackage.InnerText;
                    
           //         if (string.IsNullOrEmpty(pePackageName))
           //         {
           //             WriteLog("Error! WinPE package name specified in XML was empty!");
           //             return InstallerReturnValue.Error;
           //         }
           //         WriteLog("Adding the " + pePackageName + " package to WinPE.");

           //         retVal = InstallPackageToWinPe(tempWimFile.FullName, mountPathWinDir, pePackageName);
           //         if (retVal != 0)
           //         {
           //             WriteLog("Error occurred while trying to install the package into WinPE: " + pePackageName);
           //             UnMountWimFile(mountPath, false);
           //             return InstallerReturnValue.Error;
           //         }
           //         WriteLog("Added successfully."); 
           //     }
           // }

           // //Change scratch space if specified
           // string scratchSpace = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//ScratchSpace");
           // if (string.IsNullOrEmpty(scratchSpace) == false)
           // {
           //     WriteLog("Updating scratch space in WinPE to this setting: " + scratchSpace);

           //     retVal = ChangeWinPeScratchSpace(mountPathWinDir, scratchSpace, architecture);
           //     if (retVal != 0)
           //     {
           //         WriteLog("Error occurred while trying to update scratch space in WinPE");
           //         UnMountWimFile(mountPath, false); 
           //         return InstallerReturnValue.Error;
           //     }
           //     WriteLog("Updated successfully.");
           // }

           // // Prep WinPE (only for WAIK prior to 3.0)
            
           // WriteLog("Running 'Prep' on WinPE"); 
           // retVal = PrepWinPeImage( mountPath);
           // if (retVal != 0)
           // {
           //     WriteLog("Error occurred while trying issue a 'prep' command to WinPE");
           //     return InstallerReturnValue.Error;
           // }

           // // Unmount WinPE
           // WriteLog("Unmounting WinPE Image"); 
           // bool commitChanges = true;
           // retVal = UnMountWimFile( mountPath, commitChanges);
           // if (retVal != 0)
           // {
           //     WriteLog("Error occurred while trying unmount the WinPE image");
           //     return InstallerReturnValue.Error;
           // }

           // // Export WinPE
           // WriteLog("Exporting WinPE Image"); 
           // retVal = ExportWimFile( tempWimPath, newWimPath, imageIndex);
           // if (retVal != 0)
           // {
           //     WriteLog("Error occurred while trying export WinPE image");
           //     return InstallerReturnValue.Error;
           // }
            
            
           // if (File.Exists(newWimPath) == false)
           // {
           //     WriteLog("Error! New WIM file does not exist: " + newWimPath);
           //     return InstallerReturnValue.Error;
           // }
           // WriteLog("Creating an instance of SMS_BootImagePackage"); 
           // IResultObject bootImage = IntegrationKitUtilities.CreateNewBootImage(Connection, packageName);
           // if (bootImage == null)
           // {
           //     WriteLog("ImportBootWim failed to return a valid boot image object. Cannot continue.");
           //     return InstallerReturnValue.Error;
           // }

           // //bootImage.Get();   //refresh for lazy properties

           // newWimPath = newWimPath.Replace(configMgrDirectory, configMgrUNC);
            

           // // Populate new boot image package properties.
           // bootImage["Name"].StringValue = packageName;
           // bootImage["Description"].StringValue = packageDesc;
           // bootImage["ImagePath"].StringValue = newWimPath; // UNC path required.
           // bootImage["ImageIndex"].IntegerValue = imageIndex; // Index into WIM file for image.
           // bootImage["PkgSourceFlag"].IntegerValue = 2; // 
           // bootImage["PackageType"].IntegerValue = 258; // boot image
           // string labShell = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//EnableLabShell");
           // bool enableLabShell = false; 
           // if (string.IsNullOrEmpty(labShell) == false)
           // {
                
           //     if (bool.TryParse(labShell, out enableLabShell) == true)
           //     {
           //         bootImage["EnableLabShell"].BooleanValue = enableLabShell;
           //     }
           // }
           // bootImage["Version"].StringValue = packageVersion;
           // string bitmapPath = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//BackgroundBitmapPath");
           // if (string.IsNullOrEmpty(bitmapPath) == false)
           // {
           //     bootImage["BackgroundBitmapPath"].StringValue = bitmapPath;
           // }

           // WriteLog("SMS_BootImagePackage properties:");
           // WriteLog("Name                 : " + packageName);
           // WriteLog("Description          : " + packageDesc);
           // WriteLog("ImagePath            : " + newWimPath);
           // WriteLog("ImageIndex           : " + imageIndex);
           // WriteLog("PkgSourceFlag        : " + bootImage["PkgSourceFlag"].IntegerValue);
           // WriteLog("PackageType          : " + bootImage["PackageType"].IntegerValue);
           // WriteLog("EnableLabShell       : " + enableLabShell);
           // WriteLog("BackgroundBitmapPath : " + bitmapPath); 
            


           // // Save new package and new package properties.
           //// bootImage.AutoCommit = true;
           // bootImage.Put();

           // WriteXmlLog(NodeType.BootImagePackage, bootImage, ID);

           // if (ProcessFolderTaskForObject(bootImageNode, bootImage, IntegrationKitUtilities.ContainerItemType.BootImagePackage) != InstallerReturnValue.Success)
           // {
           //     return InstallerReturnValue.Error;
           // }
           // WriteLog("Completed processing the boot image.");
           // return InstallerReturnValue.Success;
        }

        /// <summary>
        /// Enhanced "delete" functionality for WIM files. Will unmount mounted WIMs and has greater failure prevention than a simple "delete" command.
        /// </summary>
        /// <param name="wimPath">Full path and filename of the existing WIM file.</param>
        /// <returns>A return code indicating success or failure.</returns>
        private InstallerReturnValue DeleteWimFile(string wimPath)
        {
            if (File.Exists(wimPath))
            {
                WriteLog("DeleteWimFile: Found the existing WIM file to delete (" + wimPath + ").");

                try
                {
                    File.Delete(wimPath);
                    WriteLog("DeleteWimFile: Successfully deleted the existing .wim file");
                    return InstallerReturnValue.Success;
                }
                catch (UnauthorizedAccessException ex1)
                {
                    WriteError("DeleteWimFile: Security error trying to remove the old WIM file.\n\n" + ex1.Message + "\n" + ex1.Data + "\n" + ex1.InnerException);
                    return InstallerReturnValue.Error;
                }
                catch (IOException ex)
                {
                    WriteLog("DeleteWimFile: Exception occurred while trying to delete the WIM file. This may mean the WIM is mounted. Trying to unmount.");
                    string pathName = GetFileParentDirectory(wimPath);

                    if (UnMountWimFile(Path.Combine(pathName, "temp"), false) != InstallerReturnValue.Success)
                    {
                        WriteLog("DeleteWimFile: Unmount was not successful. Exception info: \n" + ex.StackTrace);
                        return InstallerReturnValue.Error;
                    }
                    try
                    {
                        File.Delete(wimPath);
                        WriteLog("DeleteWimFile: Successfully deleted the existing .wim file");
                        return InstallerReturnValue.Success;
                    }
                    catch (Exception ex2)
                    {
                        WriteLog("DeleteWimFile: An exception still occurred trying to move the WIM file. Cannot continue. Exception info: \n" + ex2.StackTrace);
                        return InstallerReturnValue.Error;
                    }
                }
            }
            else
            {
                WriteLog("Did not find existing WIM file to delete: " + wimPath);
                return InstallerReturnValue.Success;
            }
        }


        /// <summary>
        /// Enhanced "move" or "rename" functionality for WIM files. Will unmount mounted WIMs and has greater failure prevention than a simple "move" command.
        /// </summary>
        /// <param name="currentWimPath">Full path and filename of the existing WIM file.</param>
        /// <param name="newWimPath">The full path and filename to which the existing file will me moved.</param>
        /// <returns>A return code indicating success or failure.</returns>
        private InstallerReturnValue MoveOldWimFile(string currentWimPath, string newWimPath)
        {
            if (File.Exists(currentWimPath))
            {
                WriteLog("MoveOldWimFile: Found an existing WIM file.");
                WriteLog("MoveOldWimFile: Renaming : " + currentWimPath);
                WriteLog("MoveOldWimFile:       To : " + newWimPath);

                try
                {
                    if (File.Exists(newWimPath))
                    {
                        //
                        // modified 8/18/09 by rhearn - Changed infinite renaming to deleting of old boot.wim files.
                        //
                        WriteLog("MoveOldWimFile: Found an existing WIM file with the same name as the target backup name. Will try to delete it.");
                        try
                        {
                            //string newBackupWimPath = newWimPath + DateTime.Now.Day.ToString() + DateTime.Now.Month.ToString() + DateTime.Now.Year.ToString() + DateTime.Now.Ticks.ToString();
                            //File.Move(newWimPath, newBackupWimPath);
                            DeleteWimFile(newWimPath);
                        }
                        catch (System.UnauthorizedAccessException ex1)
                        {
                            WriteError("MoveOldWimFile: Security error trying to remove the old WIM file: " + currentWimPath + "\n" + ex1.Message + "\n" + ex1.Data + "\n" + ex1.InnerException);
                            newWimPath = "alt_" + newWimPath;
                        }
                    }

                    File.Move(currentWimPath, newWimPath);
                    WriteLog("MoveOldWimFile: Successfully renamed the existing .wim file to " + newWimPath);
                    return InstallerReturnValue.Success;
                }
                catch (IOException ex)
                {
                    WriteLog("MoveOldWimFile: Exception occurred while trying to rename the WIM file. This may mean it's mounted. Trying to unmount.");
                    string pathName = GetFileParentDirectory(newWimPath);

                    if (UnMountWimFile(Path.Combine(pathName, "temp"), false) != InstallerReturnValue.Success)
                    {
                        WriteLog("MoveOldWimFile: Unmount was not successful. Exception info: \n" + ex.StackTrace);
                        return InstallerReturnValue.Error;
                    }
                    try
                    {
                        File.Move(currentWimPath, newWimPath);
                    }
                    catch (Exception ex2)
                    {
                        WriteLog("MoveOldWimFile: An exception still occurred trying to move the WIM file. Cannot continue. Exception info: \n" + ex2.StackTrace);
                        return InstallerReturnValue.Error;
                    }
                    WriteLog("MoveOldWimFile: Successfully renamed the existing .wim file to " + newWimPath);
                    return InstallerReturnValue.Success;
                }
            }
            else
            {
                WriteLog("Did not find existing WIM file to move: " + currentWimPath);
                return InstallerReturnValue.Success;
            }
        }

        /// <summary>
        /// This method has been deprecated. Please use CreateBootWim()
        /// </summary>
        /// <param name="bootImageNode"></param>
        /// <returns></returns>
        private InstallerReturnValue CreateBootWimFromExistingWim(XmlNode bootImageNode)
        {
            if (IntegrationKitUtilities.IsValidXmlElement(bootImageNode) == false)
            {
                if (bootImageNode.NodeType == XmlNodeType.Comment)
                {
                    WriteLog("Node was a comment - skipping.\n");
                    return InstallerReturnValue.Success;
                }
                WriteLog("node parameter passed in to ProcessBootImagePackage was not a valid XML element. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }

            if (Connection == null)
            {
                WriteLog("Connection to SCCM server is not valid. Cannot continue.");
                return InstallerReturnValue.ConnectionInvalid;
            }

            //=================================================================================
            //
            // modified 8/11/09 by rhearn
            // - The remainder of this method has been commented out. 
            //   Calling this method results in redirection to the new "CreateBootWim" method.
            //
            //=================================================================================
            string architecture = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Architecture");
            if (string.Compare(architecture, "x64", StringComparison.OrdinalIgnoreCase) == 0)
            {
                architecture = "amd64";
            }
            else if (IsWaikArchStringValid(architecture) == false)
            {
                architecture = "x86";
            }

            return CreateBootWim(bootImageNode, GetExistingBootWim(bootImageNode));

            
            
            //WriteLog("Creating a new boot image from existing SCCM boot.wim file");
            
            //string ID = IntegrationKitUtilities.GetXmlAttribute(bootImageNode, "ID");
            //string packageName = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Name");
            //string packageDesc = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Description");
            //string minOsVersion = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//MinOsVersion");

                
            //// Copy the WIM file from the existing path to the new path
            //string existingImage = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//PkgSourcePath");
            //XmlNode existingImagePathNode = IntegrationKitUtilities.GetXmlNode(bootImageNode, ".//PkgSourcePath");
            //existingImage = ParseRelativePath(existingImage, existingImagePathNode);
            //if (string.IsNullOrEmpty(existingImage))
            //{
            //    WriteLog("Error! existingImage was null after parsing relative path!\n");
            //    return InstallerReturnValue.Error;
            //}
            //WriteLog("Path to boot image being copied: " + existingImage);
            //FileInfo fi = new FileInfo(existingImage);
            //if (fi == null)
            //{
            //    WriteLog("Error! Existing WIM image does not exist : " + existingImage);
            //    return InstallerReturnValue.Error;
            //}

            //string waikPath = GetWaikPath();
            //if (string.IsNullOrEmpty(waikPath))
            //{
            //    WriteLog("Error! Could not determine the path to the WAIK utilities.");
            //    return InstallerReturnValue.Error;
            //}

            //if (string.IsNullOrEmpty(minOsVersion) == false)
            //{
            //    WriteLog("Minimum WinPE version specified for the boot image: " + minOsVersion);
                
            //    Version bootImageVersion = GetWimVersion(existingImage);
            //    if (bootImageVersion == null)
            //    {
            //        WriteLog("Error! Could not determine the version of the WinPE boot image : " + existingImage);
            //        return InstallerReturnValue.Error;
            //    }

            //    WriteLog("Current boot image OS version = " + bootImageVersion.ToString(4));
            //    Version targetVer = new Version(minOsVersion);
            //    if (bootImageVersion < targetVer)
            //    {
            //        WriteLog("Boot image WinPE version does not meet requirements. Please upgrade WAIK and Configuration Manager to upgrade the boot images.");
            //        return InstallerReturnValue.Error;
            //    }
            //}

      
            //string newWimPath = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//ImageImportPath");
            //XmlNode pathNode = IntegrationKitUtilities.GetXmlNode(bootImageNode, ".//ImageImportPath");
            //newWimPath = ParseRelativePath(newWimPath, pathNode);
            //if (string.IsNullOrEmpty(newWimPath))
            //{
            //    WriteLog("Error! newWimPath was null after parsing relative path!\n");
            //    return InstallerReturnValue.Error;
            //}
            //WriteLog("Path to boot image after export: " + newWimPath);

            //int pos = newWimPath.LastIndexOf("\\");
            //string pathName = GetFileParentDirectory(newWimPath);
            //string fileName = newWimPath.Substring(pos + 1);
            //if (Directory.Exists(pathName) == false)
            //{
            //    try
            //    {
            //        DirectoryInfo wimDir = Directory.CreateDirectory(pathName);
            //    }
            //    catch (Exception ex)
            //    {
            //        WriteLog("Exception occurred while creating the directory for the WIM file." + ex.StackTrace);
            //        return InstallerReturnValue.Error;
            //    }
            //}
            //if (File.Exists(newWimPath))
            //{
            //    WriteLog("Found an existing boot.wim file. Renaming...");
            //    string oldWim = newWimPath + ".old";

            //    try
            //    {
            //        if (File.Exists(oldWim))
            //        {
            //            try
            //            {
            //                File.Delete(oldWim);
            //            }
            //            catch (System.UnauthorizedAccessException ex1)
            //            {
            //                string errorText = "Security error trying to remove the old WIM file: " + oldWim + "\n" + ex1.Message + "\n" + ex1.Data + "\n" + ex1.InnerException;
            //                WriteError(errorText);
            //                oldWim = oldWim += ".old";
            //            }
            //        }

            //        File.Move(newWimPath, oldWim);
            //        WriteLog("Successfully renamed the old .wim file to " + oldWim);
            //    }
            //    catch(IOException ex)
            //    {
            //        WriteLog("Exception occurred while trying to rename the WIM file. This may mean it's mounted. Trying to unmount.");
            //        if (UnMountWimFile(pathName + "\\temp", false) != InstallerReturnValue.Success)
            //        {
            //            WriteLog("Unmount was not successful. Exception info: \n" + ex.StackTrace );
            //            return InstallerReturnValue.Error;                    
            //        }
            //        File.Move(newWimPath, oldWim);
            //        WriteLog("Successfully renamed the old .wim file to " + oldWim);
            //    }
            //}


            //FileInfo newFile;
            //try
            //{
            //    WriteLog("Copying existing boot.wim to new file."); 
            //    newFile = fi.CopyTo(newWimPath);
            //}
            //catch (Exception ex)
            //{
            //    WriteLog("Exception occurred while copying the WIM file." + ex.StackTrace);
            //    return InstallerReturnValue.Error;
            //}
            //if (newFile == null)
            //{
            //    WriteLog("Error! Could not copy the WIM file.");
            //    return InstallerReturnValue.Error;
            //}
            //WriteLog("Copied successfully.");


            //// int imageIndex = 1;
            //string architecture = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Architecture");
            //if (string.IsNullOrEmpty(architecture))
            //{
            //    architecture = "x86";
            //}

            //WriteLog("Importing the boot image into a Configuration Manager package");
            ////packageName = null;
            //IResultObject bootImage = null;
            //try
            //{
            //    bootImage = IntegrationKitUtilities.CreateNewBootImage(connection, packageName);
            //    if (bootImage == null)
            //    {
            //        return InstallerReturnValue.Error;
            //    }
                
            //    // Populate new boot image package properties.
            //    bootImage["Name"].StringValue = packageName;
            //    bootImage["Description"].StringValue = packageDesc;
            //    bootImage["ImagePath"].StringValue = newWimPath; // UNC path required.
            //    bootImage["ImageIndex"].IntegerValue = 1; // Index into WIM file for image.
            //    bootImage["PkgSourceFlag"].IntegerValue = 2; // 
            //    bootImage["PackageType"].IntegerValue = 258; // boot image

            //    bool enableLabShell = false;
            //    if (bool.TryParse(IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//EnableLabShell"), out enableLabShell))
            //    {
            //        bootImage["EnableLabShell"].BooleanValue = enableLabShell;
            //    }
            //    bootImage["Version"].StringValue = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//Version");
            //    bootImage["BackgroundBitmapPath"].StringValue = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//BackgroundBitmapPath");

            //    // Save new package and new package properties.
            //    bootImage.AutoCommit = true;
            //    bootImage.Put();

            //}
            //catch (Exception ex1)
            //{
            //    bootImage = null;
            //    string message = ex1.Message + "\n" + ex1.StackTrace + "\n" + ex1.Data + "\n" + ex1.InnerException;
            //    WriteError(message);
            //}

            //if (bootImage == null)
            //{
            //    WriteLog("ImportBootWim failed to return a valid object. Cannot continue.");
            //    return InstallerReturnValue.Error;
            //}
            //WriteLog("Imported successfully.Saving to the installed components list");

            //WriteXmlLog(NodeType.BootImagePackage, bootImage, ID);

            //if (ProcessFolderTaskForObject(bootImageNode, bootImage, IntegrationKitUtilities.ContainerItemType.BootImagePackage) != InstallerReturnValue.Success)
            //{
            //    return InstallerReturnValue.Error;
            //}
            //WriteLog("Completed processing the boot image.");
            //return InstallerReturnValue.Success;

        }

        /// <summary>
        /// Processes the directives specified in the "BootImagePackage_InjectChanges" elements in the installer XML file.
        /// </summary>
        /// <param name="bootImageNode">An XmlNode containing the BootImagePackage_InjectChanges element and children.</param>
        /// <returns>A return code indicating success or failure.</returns>
        private InstallerReturnValue ProcessBootImageInjection(XmlNode bootImageNode)
        {
            if (bootImageNode == null)
            {
                WriteLog("ProcessBootImageInjection: bootImageNode element passed in was null. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }

            if (string.Compare(bootImageNode.Name, "BootImagePackage_InjectChanges", StringComparison.OrdinalIgnoreCase) != 0)
            {
                WriteLog("ProcessBootImageInjection: node element passed in was invalid. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }

            string ID = IntegrationKitUtilities.GetXmlAttribute(bootImageNode, "ID");
            string targetID = IntegrationKitUtilities.GetXmlNodeValue(bootImageNode, ".//PackageToModify");
            IResultObject targetPackage = null;
            string targetPackageID = GetObjectInstanceIdFromXml(targetID, NodeType.BootImagePackage);
            if (string.IsNullOrEmpty(targetPackageID))
            {
                WriteLog("ProcessBootImageInjection: Unable to locate boot image package by ID in the current installer XML: " + targetID);
                XmlNode prevBootImageNode = LookupObjectFromXmlLog(NodeType.BootImagePackage, targetID);
                if (prevBootImageNode != null)
                {
                    WriteLog("ProcessBootImageInjection: Found the boot image info in the installer XML. Getting the display name.");
                    targetID = IntegrationKitUtilities.GetXmlNodeValue(prevBootImageNode, "Name");
                }
                IResultObject targetPackages = IntegrationKitUtilities.GetPackageByName(Connection, targetID, IntegrationKitUtilities.PackageType.BootImagePackage, null);
                //targetPackage = Connection.GetInstance(@"SMS_BootImagePackage.Name='" + targetID + "'");
                if (targetPackages == null)
                {
                    WriteLog("ProcessBootImageInjection: Unable to locate boot image package by name in Config Manager either. Cannot continue.");
                    return InstallerReturnValue.InvalidParameter;
                }
                foreach (IResultObject obj in targetPackages)
                {
                    targetPackage = obj;
                    break;
                }

            }
            else
            {
                targetPackage = Connection.GetInstance(@"SMS_BootImagePackage.PackageID='" + targetPackageID + "'");
                if (targetPackage == null)
                {
                    WriteLog("ProcessBootImageInjection: Unable to locate boot image package by PackageID: " + targetPackageID);
                    return InstallerReturnValue.InvalidParameter;
                }
            }
            WriteLog("ProcessBootImageInjection: Found the boot image package");
                    
            //should now have a valid IResultObject for the package to be injected
            string baseWimPath = IntegrationKitUtilities.GetROStringProperty(targetPackage, "ImagePath");
            if (string.IsNullOrEmpty(baseWimPath))
            {
                //need this path to inject files.
                WriteLog("ProcessBootImageInjection: The target package properties did not have a value for ImagePath. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            // need to resolve base WIM path to a local directory (it is stored as UNC) and remove the file name at the end

            WriteLog("ProcessBootImageInjection: UNC path to the boot image: " + baseWimPath);

            //===[ begin modifications ]=================================
            // Modified 9/10/08 by rhearn
            // - Added new code for x64 detection and redirection of registry keys to Wow6432Node key

            string configMgrDirectory = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Installation Directory");

            //===[ end modifications ]=================================
            
            string configMgrUNC = @"\\" + serverName + @"\" + "SMS_" + siteCode;

            WriteLog("ProcessBootImageInjection: Converting the UNC path to a local path");
            baseWimPath = baseWimPath.Replace(configMgrUNC, configMgrDirectory);

            WriteLog("ProcessBootImageInjection: Local path to the boot image: " + baseWimPath);

            FileInfo fiWim = new FileInfo(baseWimPath);

            string tempPath = Path.Combine(fiWim.DirectoryName, "temp");
            if (Directory.Exists(tempPath) == false)
            {
                Directory.CreateDirectory(tempPath);
            }

            WriteLog("ProcessBootImageInjection: Boot image will be mounted to: " + tempPath);
            
            string mountPath = baseWimPath;
            string wimFilename = fiWim.Name;
            int imageIndex = 1;

            string archType = GetWimArchitecture(fiWim.FullName, imageIndex);

            if (MountWimFile(baseWimPath, tempPath, imageIndex) != InstallerReturnValue.Success)
            {
                WriteLog("ProcessBootImageInjection: Could not mount the WIM image. Cannot continue.");
                return InstallerReturnValue.Error;
            }
            WriteLog("ProcessBootImageInjection: Mounted the boot image.");
                    
            
            if (CopyFilesIntoWim(bootImageNode, tempPath) != InstallerReturnValue.Success)
            {
                UnMountWimFile(tempPath, false);
                return InstallerReturnValue.Error;
            }

            if (UpdateRegistryInWim(bootImageNode, tempPath) != InstallerReturnValue.Success)
            {
                UnMountWimFile(tempPath, false);
                return InstallerReturnValue.Error;
            }

            if (ImportDriversIntoWim(bootImageNode, tempPath, archType) != InstallerReturnValue.Success)
            {
                UnMountWimFile(tempPath, false);
                return InstallerReturnValue.Error;
            }

            // done with modifications - close the WIM up again


            if(UnMountWimFile(tempPath, true) != InstallerReturnValue.Success)
            {
                WriteLog("ProcessBootImageInjection: Could not unmount and commit the WIM image. Cannot continue.");
                return InstallerReturnValue.Error;
            }

            if (Directory.Exists(tempPath))
            {
                WriteLog("ProcessBootImageInjection: Removing the temporary mount directory.");
                Directory.Delete(tempPath, true);
            }

            //now update the boot image package

            if (string.IsNullOrEmpty(targetPackageID) == false)
            {
                WriteLog("ProcessBootImageInjection: Refreshing the image package in ConfigMgr.");
                IntegrationKitUtilities.RefreshImagePackage(connection, targetPackageID);
            }

            WriteXmlLog(NodeType.BootImagePackage, targetPackage, ID);
            return InstallerReturnValue.Success;
        }

        /// <summary>
        /// Imports Windows drivers into a mounted WIM file so they are available at runtime.
        /// </summary>
        /// <param name="bootImageNode">An XmlNode containing the BootImagePackage_InjectChanges element and children.</param>
        /// <param name="tempPath">The path to the mounted WIM image.</param>
        /// <returns>A return code indicating success or failure.</returns>
        private InstallerReturnValue ImportDriversIntoWim(XmlNode bootImageNode, string tempPath)
        {
            return ImportDriversIntoWim(bootImageNode, tempPath, "x86");
        }

        /// <summary>
        /// Imports Windows drivers into a mounted WIM file so they are available at runtime.
        /// </summary>
        /// <param name="bootImageNode">An XmlNode containing the BootImagePackage_InjectChanges element and children.</param>
        /// <param name="tempPath">The path to the mounted WIM image.</param>
        /// <param name="archType">The architecture of the image, used to determine the appropriate WAIK utilities to use.</param>
        /// <returns>A return code indicating success or failure.</returns>
        private InstallerReturnValue ImportDriversIntoWim(XmlNode bootImageNode, string tempPath, string archType)
        {
            if (bootImageNode == null)
            {
                WriteLog("ImportDriversIntoWim: bootImageNode parameter was null");
                return InstallerReturnValue.InvalidParameter;
            }

            if (string.IsNullOrEmpty(tempPath) || (Directory.Exists(tempPath) == false))
            {
                WriteLog("ImportDriversIntoWim: tempPath parameter (" + tempPath + ") was invalid.");
                return InstallerReturnValue.InvalidParameter;
            }

            XmlNodeList importDriverNodes = IntegrationKitUtilities.GetXmlNodeList(bootImageNode, ".//ImportDriver");
            if ((importDriverNodes == null) || (importDriverNodes.Count == 0))
            {
                WriteLog("ImportDriversIntoWim: No importDriverNodes to process");
                return InstallerReturnValue.Success;
            }

            if (IsWaikArchStringValid(archType) == false)
            {
                WriteLog("ImportDriversIntoWim: architecture type specified (" + archType + ") was invalid.");
                return InstallerReturnValue.InvalidParameter;
            }

           
        
            //
            //  sample driver import XML
            //
            //    <ImportDriver IsRelative="true" RelativeTo="ConfigMgrLocalInstallDir">\OSD\Deployment\Dell\PowerEdge\WinPE_boot\rac4\rac4ser.inf</ImportDriver>
            //

            // modified by rhearn
            // Moved these static info types outside of the loop to avoid having to call them each time through the loop.
            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("ImportDriversIntoWim: Path to WAIK utilities not found");
                //UnMountWimFile(tempPath, false);   
                return InstallerReturnValue.Error;
            }

            Version waikVersion = GetWaikVersion();
            //end modification

            WriteLog("ImportDriversIntoWim: Importing " + importDriverNodes.Count + " drivers into the WIM file.");
               
            for (int i = 0; i < importDriverNodes.Count; i++)
            {
                WriteLog("ImportDriversIntoWim: Importing driver [" + i + "] of [" + importDriverNodes.Count + "]");
                XmlNode driverNode = IntegrationKitUtilities.GetXmlNode(importDriverNodes[i], "./DriverSourcePath");
                string sourceFile = IntegrationKitUtilities.GetXmlNodeValue(importDriverNodes[i], "./DriverSourcePath");
                WriteLog("ImportDriversIntoWim: Source file from XML: " + sourceFile);
                sourceFile = ParseRelativePath(sourceFile, driverNode);
                WriteLog("ImportDriversIntoWim: Source file after parsing: " + sourceFile);
                
                if (string.IsNullOrEmpty(sourceFile))
                {
                    WriteLog("ImportDriversIntoWim: Invalid source file or error when parsing: " + sourceFile);
                    //UnMountWimFile(tempPath, false);
                    return InstallerReturnValue.Error;
                }
                if (File.Exists(sourceFile) == false)
                {
                    WriteLog("ImportDriversIntoWim: Source file not found: " + sourceFile);
                    //UnMountWimFile(tempPath, false);
                    return InstallerReturnValue.Error;
                }
                string destination = IntegrationKitUtilities.GetXmlNodeValue(importDriverNodes[i], "./CopyToWimPath");
                //modified 9/14/09 by rhearn to fix bug 5580
                if (string.IsNullOrEmpty(destination))
                {
                    destination = tempPath;
                }
                else
                {
                    destination = Path.Combine(tempPath, destination);
                }
                //destination = Path.Combine(tempPath, destination);

                WriteLog("ImportDriversIntoWim: Destination path is set to: " + destination);
                if (Directory.Exists(destination) == false)
                {
                    WriteLog("DImportDriversIntoWim: estination directory not found: " + destination);
                    //UnMountWimFile(tempPath, false);
                    return InstallerReturnValue.Error;
                }
                               

                //modified 6/16/09 by rhearn
                // - Added support for WAIK 3.0 utilities

                sourceFile = "\"" + sourceFile + "\"";
                tempPath = "\"" + tempPath + "\"";
                string cmdLine = string.Empty;
                string args = string.Empty;
                string workingDir = string.Empty;
                if ((waikVersion.Major == 6) && (waikVersion.Minor == 0))
                {
                    cmdLine = GetPeImgPath();
                    workingDir = GetFileParentDirectory(cmdLine);
                    args = "/inf=" + "\"" + sourceFile + "\"" + " \"" + tempPath + "\"";
                }
                else if ((waikVersion.Major == 6) && (waikVersion.Minor == 1))
                {
                    cmdLine = GetDismPath(archType);
                    workingDir = GetFileParentDirectory(cmdLine);
                    args = "/image:" + tempPath + " /Add-Driver /driver:" + sourceFile + " /ForceUnsigned";
                }
                else
                {
                    WriteLog("ImportDriversIntoWim: WAIK version is not supported");
                    //UnMountWimFile(tempPath, false);
                    return InstallerReturnValue.Error;
                }
                if (File.Exists(cmdLine) == false)
                {
                    WriteLog("ImportDriversIntoWim: Could not find the WAIK utility at : " + cmdLine);
                    //UnMountWimFile(tempPath, false);
                    return InstallerReturnValue.Error;
                }

                //workingDir = "\"" + workingDir + "\"";
                string output = string.Empty;
                int retVal = RunCommandLine.RunExe(cmdLine, workingDir, args, 30000, out output);
                WriteLog(output);
                if (retVal != 0)
                {
                    //UnMountWimFile(tempPath, false);
                    return InstallerReturnValue.Error;
                }

            }
            return InstallerReturnValue.Success;
        }

        /// <summary>
        /// Modifies registry settings within a mounted WIM image based on .reg files or specific key strings.
        /// </summary>
        /// <param name="bootImageNode">An XmlNode containing the BootImagePackage_InjectChanges element and children.</param>
        /// <param name="mountPath">The path to the mounted WIM image.</param>
        /// <returns>A return code indicating success or failure.</returns>
        private InstallerReturnValue UpdateRegistryInWim(XmlNode bootImageNode, string mountPath)
        {
            WriteLog("UpdateRegistryInWim: Updating the registry hives in the WIM");

            if (bootImageNode == null)
            {
                WriteLog("UpdateRegistryInWim: bootImageNode was null");
                return InstallerReturnValue.InvalidParameter;
            }
            
            XmlNodeList updateRegNodes = IntegrationKitUtilities.GetXmlNodeList(bootImageNode, ".//RegistryUpdate");
            if ((updateRegNodes == null) || (updateRegNodes.Count == 0))
            {
                WriteLog("UpdateRegistryInWim: No updateRegNodes to process");
                return InstallerReturnValue.Success;
            }
            WriteLog("UpdateRegistryInWim: There are [" + updateRegNodes.Count + "] registry updates to process.");
            
            string regCmd = Path.Combine(System.Environment.SystemDirectory, "reg.exe");
                        
            for (int i = 0; i < updateRegNodes.Count; i++)
            {
                XmlNode currentNode = updateRegNodes[i];
                string hiveName = IntegrationKitUtilities.GetXmlAttribute(currentNode, "HiveName");
                if (string.IsNullOrEmpty(hiveName))
                {
                    WriteLog("UpdateRegistryInWim: Hive name was null");
                    //UnMountWimFile(mountPath, false);
                    return InstallerReturnValue.InvalidParameter;
                }
                if (currentNode.HasChildNodes == false)
                {
                    WriteLog("UpdateRegistryInWim: Error! There are no child nodes to process.");
                    //UnMountWimFile(mountPath, false);
                    return InstallerReturnValue.InvalidParameter;
                }
                
                //now import the individual registry files
                for (int j = 0; j < currentNode.ChildNodes.Count; j++)
                {
                    //open the hive
                    WriteLog("UpdateRegistryInWim: Running regedit to mount the hive for editing: " + hiveName);
                    string output = string.Empty;
                    string systemHive = Path.Combine(mountPath, "Windows" + Path.DirectorySeparatorChar + "system32" + Path.DirectorySeparatorChar + "config" + Path.DirectorySeparatorChar + "SYSTEM");
                    if (File.Exists(systemHive) == false)
                    {
                        WriteLog("UpdateRegistryInWim: Unable to find the system hive at: " + systemHive);
                        //UnMountWimFile(mountPath, false);
                        return InstallerReturnValue.Error;
                    }

                    int retval = RunCommandLine.RunExe(regCmd, "", "load " + "\"" + hiveName + "\\hiv\" " + "\"" + systemHive + "\"", 5000, out output);
                    WriteLog(output);

                    if (retval != 0)
                    {
                        WriteLog("UpdateRegistryInWim: n error occurred mounting the hive : " + hiveName);
                        //UnMountWimFile(mountPath, false);
                        return InstallerReturnValue.InvalidParameter;
                    }

                    WriteLog("UpdateRegistryInWim: Successfully mounted the hive.");
                        
                    string sourceFile = IntegrationKitUtilities.GetXmlNodeValue(currentNode.ChildNodes[j], ".");
                    sourceFile = ParseRelativePath(sourceFile, currentNode.ChildNodes[j]);
                    if (string.IsNullOrEmpty(sourceFile))
                    {
                        WriteLog("UpdateRegistryInWim: Invalid source file or error when parsing: " + sourceFile);
                        //UnMountWimFile(mountPath, false);
                        return InstallerReturnValue.Error;
                    }
                    if (File.Exists(sourceFile) == false)
                    {
                        WriteLog("UpdateRegistryInWim: Source file not found: " + sourceFile);
                        //UnMountWimFile(mountPath, false);
                        return InstallerReturnValue.Error;
                    }
                    WriteLog("UpdateRegistryInWim: Running regedit to import the registry info from file: " + sourceFile);
                    output = string.Empty;
                    retval = RunCommandLine.RunExe(regCmd, "", "import " + "\"" + sourceFile + "\"", 5000, out output);
                    WriteLog(output);
                    if (retval != 0)
                    {
                        WriteLog("UpdateRegistryInWim: An error occurred importing the registry file");
                        //UnMountWimFile(mountPath, false);
                        return InstallerReturnValue.InvalidParameter;
                    }

                    WriteLog("UpdateRegistryInWim: Closing the registry hive: " + hiveName);
                    output = string.Empty;
                    retval = RunCommandLine.RunExe(regCmd, "", "unload " + "\"" + hiveName + "\\hiv\"", 5000, out output);
                    WriteLog(output);
                    if (retval != 0)
                    {
                        WriteLog("UpdateRegistryInWim: An error occurred unmounting the hive");
                        //UnMountWimFile(mountPath, false);
                        return InstallerReturnValue.InvalidParameter;
                    }
                }
            }
            WriteLog("UpdateRegistryInWim: Done with registry imports");
            
            return InstallerReturnValue.Success;
        }

        /// <summary>
        /// Copies files and directories from a given path (specified in the XML) into specific locations in a mounted WIM image.
        /// </summary>
        /// <param name="bootImageNode">An XmlNode containing the BootImagePackage_InjectChanges element and children.</param>
        /// <param name="mountPath">The path to the mounted WIM image.</param>
        /// <returns>A return code indicating success or failure.</returns>
        private InstallerReturnValue CopyFilesIntoWim(XmlNode bootImageNode, string mountPath)
        {
            if (bootImageNode == null)
            {
                WriteLog("CopyFilesIntoWim: bootImageNode was null");
                return InstallerReturnValue.InvalidParameter;
            }

            if (string.IsNullOrEmpty(mountPath) || (Directory.Exists(mountPath) == false))
            {
                WriteLog("CopyFilesIntoWim: mountPath parameter specified (" + mountPath + ") was invalid.");
                return InstallerReturnValue.InvalidParameter;
            }

            XmlNodeList copyFilesNodes = IntegrationKitUtilities.GetXmlNodeList(bootImageNode, ".//CopyFileToWim");
            if ((copyFilesNodes == null) || (copyFilesNodes.Count == 0))
            {
                WriteLog("No copyFilesNodes to process");
                return InstallerReturnValue.Success;
            }
            WriteLog("Copying files into WIM");

            for (int i = 0; i < copyFilesNodes.Count; i++)
            {
                XmlNode currentNode = copyFilesNodes[i];
                string isDirectory = IntegrationKitUtilities.GetXmlAttribute(currentNode, "IsDirectory");
                string sourceFile = IntegrationKitUtilities.GetXmlNodeValue(currentNode, "./CopyFromPath");
                string destination = IntegrationKitUtilities.GetXmlNodeValue(currentNode, "./CopyToWimPath");
                sourceFile = ParseRelativePath(sourceFile, IntegrationKitUtilities.GetXmlNode(currentNode, "./CopyFromPath"));

                //sourceFile = baseSourcePath + @"\" + sourceFile;
                WriteLog("configMgrDirectory is set to: " + sourceFile);

                //modified 9/14/09 by rhearn to fix bug 5580
                if (string.IsNullOrEmpty(destination))
                {
                    destination = mountPath;
                }
                else
                {
                    destination = Path.Combine(mountPath, destination);
                }
                WriteLog("Destination path is set to: " + destination);
                
                if (string.Compare(isDirectory, "true", StringComparison.OrdinalIgnoreCase) == 0)
                {
                    //copy the directory, not just a file
                    if (Directory.Exists(sourceFile) == false)
                    {
                        WriteLog("The source directory to be copied was not found: " + sourceFile);
                        //UnMountWimFile(mountPath, false);
                        return InstallerReturnValue.Error;
                    }
                    IntegrationKitUtilities.CopyDirectory(sourceFile, destination);
                    WriteLog("Copied all files from '" + sourceFile + "' into WIM");

                }
                else
                {
                    //copy a file
                    if (File.Exists(sourceFile) == false)
                    {
                        WriteLog("The source file to be copied was not found: " + sourceFile);
                        //UnMountWimFile(mountPath, false);
                        return InstallerReturnValue.Error;
                    }
                    FileInfo fi = new FileInfo(sourceFile);
                    if (fi == null)
                    {
                        WriteLog("Error creating Fileinfo object for file: " + sourceFile);
                        //UnMountWimFile(mountPath, false);
                        return InstallerReturnValue.Error;
                    }
                    try
                    {
                        File.Copy(sourceFile, destination + fi.Name, true);
                        WriteLog("Copied file '" + fi.Name + "' into WIM");
                    }
                    catch (Exception fex)
                    {
                        WriteLog("Exception encountered while copying file: " + sourceFile + "\n\n" + fex.Message);
                        //UnMountWimFile(mountPath, false);
                        return InstallerReturnValue.Error;
                    }

                }

            }
            WriteLog("Finished copying files into WIM");
            return InstallerReturnValue.Success;
            // Done with file copying
        }

        /// <summary>
        /// This method has been deprecated. Please use InstallPackagetoWinPe()
        /// </summary>
        /// <param name="bootImageNode"></param>
        /// <param name="mountPath"></param>
        /// <returns></returns>
        private InstallerReturnValue InstallWinPePackagesIntoWim(XmlNode bootImageNode, string mountPath)
        {
            try
            {
                if (bootImageNode == null)
                {
                    WriteLog("bootImageNode was null");
                    return InstallerReturnValue.InvalidParameter;
                }

                XmlNodeList packageNodes = IntegrationKitUtilities.GetXmlNodeList(bootImageNode, ".//AddPackage");
                if ((packageNodes == null) || (packageNodes.Count == 0))
                {
                    WriteLog("No AddPackage nodes to process");
                    return InstallerReturnValue.Success;
                }

                // modified by rhearn
                // Removed from the loop
                string waikPath = GetWaikPath();
                if (string.IsNullOrEmpty(waikPath))
                {
                    WriteLog("Could not locate WAIK path");
                    return InstallerReturnValue.Error;
                }
                DirectoryInfo di = new DirectoryInfo(waikPath);
                if (di == null)
                {
                    WriteLog("Could not get directory info from WAIK path. Does directory exist?");
                    return InstallerReturnValue.Error;
                }
                //end modification

                for (int i = 0; i < packageNodes.Count; i++)
                {
                    XmlNode currentNode = packageNodes[i];
                    string packageName = IntegrationKitUtilities.GetXmlNodeValue(currentNode, ".");
                    WriteLog("Adding WinPE Package: " + packageName);
                    
                    waikPath = Path.Combine( di.FullName, "Tools" + Path.DirectorySeparatorChar + "PETools");

                    string cmdline = Path.Combine( waikPath, "peimg.exe");
                    string args = "/install=" + packageName + " \""+ mountPath + Path.DirectorySeparatorChar + "Windows\"";
                    string results = string.Empty;
                    WriteLog("Running PEIMG.EXE command line:"); 
                    int retVal = RunCommandLine.RunExe(cmdline, waikPath, args, 300, out results);
                    WriteLog(results);
                    if (retVal != 0)
                    {
                        WriteLog("Error returned from running peimg.exe: " + retVal.ToString());
                        return InstallerReturnValue.Error;
                    }
                    WriteLog("Successfully added package");
                }
                return InstallerReturnValue.Success;
                // Done with file copying
            }
            catch (Exception ex)
            {
                WriteError("Exception occurred while trying to install WinPE packages." + ex.Message);
                return InstallerReturnValue.Exception;
            }

        }

        /// <summary>
        /// Mounts a WIM image to a specified directory.
        /// </summary>
        /// <param name="wimFile">The full path and filename of the WIM image to mount.</param>
        /// <param name="tempPath">The path where the WIM image will be mounted.</param>
        /// <returns>A return code indicating success or failure.</returns>
        private InstallerReturnValue MountWimFile(string wimFile, string tempPath)
        {
            return MountWimFile(wimFile, tempPath, 1);
        }

        /// <summary>
        /// Mounts a WIM image to a specified directory.
        /// </summary>
        /// <param name="wimFile">The full path and filename of the WIM image to mount.</param>
        /// <param name="tempPath">The path where the WIM image will be mounted.</param>
        /// <param name="imageIndex">The index of the image in the WIM file to be mounted</param>
        /// <returns>A return code indicating success or failure.</returns>
        private InstallerReturnValue MountWimFile(string wimFile, string tempPath, int imageIndex)
        {

            if (string.IsNullOrEmpty(wimFile))
            {
                WriteLog("MountWimFile: wimFile parameter specified was null");
                return InstallerReturnValue.InvalidParameter;
            }
            if (File.Exists(wimFile) == false)
            {
                WriteLog("MountWimFile: Could not find the WIM file at : " + wimFile);
                return InstallerReturnValue.Error;
            }
            if (string.IsNullOrEmpty(tempPath))
            {
                WriteLog("MountWimFile: wimFile parameter specified (" + tempPath+ ") was null");
                return InstallerReturnValue.InvalidParameter;
            }

            if (imageIndex < 1)
            {
                WriteLog("MountWimFile: imageIndex parameter specified (" + imageIndex + ") was invalid");
                return InstallerReturnValue.InvalidParameter;
            }


            
            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("Could not get the path to the WAIK utilities.");
                return InstallerReturnValue.Error;
            }

            if (tempPath.StartsWith("\\"))
            {

                string configMgrDirectory = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Installation Directory");
                string configMgrUNC = @"\\" + serverName + @"\" + "SMS_" + siteCode;

                WriteLog("Converting UNC path to local path");
                tempPath = tempPath.Replace(configMgrUNC, configMgrDirectory);
                WriteLog("Local path to boot image: " + tempPath);
            }
            if (Directory.Exists(tempPath) == false)
            {
                try
                {
                    Directory.CreateDirectory(tempPath);
                }
                catch (Exception e)
                {
                    WriteLog("MountWimFile: An exception occurred while trying to create the temporary mount directory:\n" + e.StackTrace);
                    return InstallerReturnValue.Error;
                }
            }
            
            string cmdLine = GetImagexPath(GetWimArchitecture(wimFile, imageIndex ), waikPath);
            string workingDir = GetFileParentDirectory(cmdLine);
            if (string.IsNullOrEmpty(cmdLine))
            {
                return InstallerReturnValue.Error;
            }

            WriteLog("MountWimFile: Running : " + cmdLine);
            
            string args = "/mountrw " + "\"" + wimFile + "\"" + " " + imageIndex + " " + "\"" + tempPath + "\"";
            
            WriteLog("argument string : " + args);

            int retVal = 0;
            string output = string.Empty;
            retVal = RunCommandLine.RunExe(cmdLine, workingDir, args, 30000, out output);
            WriteLog(output);
            if (retVal != 0)
            {
                WriteLog("MountWimFile: Error mounting the file. The return code was '" + retVal + "'");
                return InstallerReturnValue.Error;
            }
            WriteLog("MountWimFile: Successfully mounted the file."); 
            return InstallerReturnValue.Success;

        }

        /// <summary>
        /// Unmounts a WIM image from its temporary structure.
        /// </summary>
        /// <param name="tempPath">The path to where the WIM file is currently mounted.</param>
        /// <param name="commit">True saves changes to the WIM, False discards all changes.</param>
        /// <returns>A return code indicating success or failure.</returns>
        private InstallerReturnValue UnMountWimFile(string tempPath, bool commit)
        {
            //if (commit == false)
            //{
            //    return InstallerReturnValue.Error;
            //}

            int retVal = 0;
            if (Directory.Exists(tempPath) == false)
            {
                WriteLog("Could not get the path to the mounted WIM file.");
                return InstallerReturnValue.Error;
            }
            if (tempPath.StartsWith("\\"))
            {
                //===[ begin modifications ]=================================
                // Modified 9/10/08 by rhearn
                // - Added new code for x64 detection and redirection of registry keys to Wow6432Node key

                string configMgrDirectory = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Installation Directory");

                //===[ end modifications ]=================================

                string configMgrUNC = @"\\" + serverName + @"\" + "SMS_" + siteCode;
            
                WriteLog("Replacing path in WIM directory value (to be able to access the WIM via local path)");
                tempPath = tempPath.Replace(configMgrUNC, configMgrDirectory);
                WriteLog("tempPath: " + tempPath);
            }


            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("Could not get the path to the WAIK utilities.");
                return InstallerReturnValue.Error;
            }
            string cmdLine = GetImagexPath();
            if (string.IsNullOrEmpty(cmdLine))
            {
                return InstallerReturnValue.Error;
            }
            string workingDir = GetFileParentDirectory(cmdLine);
            
            string args = string.Empty;
            if (commit)
            {
                args = "/unmount /commit " + "\"" + tempPath + "\"";
            }
            else
            {
                args = "/unmount " + "\"" + tempPath + "\"";
            }

            string output = string.Empty;
            retVal = RunCommandLine.RunExe(cmdLine, workingDir, args, 30000, out output);
            WriteLog(output);
            if (retVal != 0)
            {
               return InstallerReturnValue.Error;
            }
            return InstallerReturnValue.Success;
    
        }

        /// <summary>
        /// Compares the string provided against valid architecture types and returns a boolean value of the result.
        /// </summary>
        /// <param name="archType">A string value containing the architecture type.</param>
        /// <returns>True if the string is valid, false otherwise or on error.</returns>
        private bool IsWaikArchStringValid(string archType)
        {
            if ((string.Compare(archType, "x86", StringComparison.OrdinalIgnoreCase) == 0) ||
                (string.Compare(archType, "amd64", StringComparison.OrdinalIgnoreCase) == 0) ||
                (string.Compare(archType, "ia64", StringComparison.OrdinalIgnoreCase) == 0))
            {
                WriteLog("IsArchStringValid: Architecture type specified (" + archType + ") was valid.");
                return true;
            }
            WriteLog("IsArchStringValid: Architecture type specified (" + archType + ") was not valid.");
            return false;
        }
        
        /// <summary>
        /// Locates the imagex.exe utility within the installed WAIK and returns the path.
        /// If not specified, "x86" is used as the architecture.
        /// </summary>
        /// <returns>A string containing the full path and file name of the imagex.exe utility, or null if not found or on error.</returns>
        private string GetImagexPath()
        {
            return GetImagexPath(IntegrationKitUtilities.GetCPUArchitecture(), GetWaikPath());
        }

        
        /// <summary>
        /// Locates the imagex.exe utility within the installed WAIK and returns the path.
        /// </summary>
        /// <param name="archType">The architecture type of the utility to be found.</param>
        /// <returns>A string containing the full path and file name of the imagex.exe utility, or null if not found or on error.</returns>
        private string GetImagexPath(string archType, string waikPath)
        {
            if (IsWaikArchStringValid(archType) == false)
            {
                return null;
            }
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("GetImagexPath: Path to the WAIK utilities passed in was null.");
                return null;
            }
            string toolArchitecture = GetWaikToolsArchitecture(archType);

            string imagexPath = Path.Combine(waikPath, "Tools" + Path.DirectorySeparatorChar + toolArchitecture + Path.DirectorySeparatorChar + "imagex.exe");
            if (File.Exists(imagexPath) == false)
            {
                WriteLog("GetImagexPath: Could not find the imagex.exe utility at : " + imagexPath);
                return null;
            }
            return imagexPath;
        }

        /// <summary>
        /// Locates the dism.exe utility within the installed WAIK for the current CPU architecture and returns the path.
        /// </summary>
        /// <returns>A string containing the full path and file name of the dism.exe utility, or null if not found or on error.</returns>
        private string GetDismPath()
        {
            return GetDismPath(IntegrationKitUtilities.GetCPUArchitecture());
        }

        /// <summary>
        /// Locates the dism.exe utility within the installed WAIK and returns the path.
        /// </summary>
        /// <returns>A string containing the full path and file name of the dism.exe utility, or null if not found or on error.</returns>
        private string GetDismPath(string archType)
        {
            if (IsWaikArchStringValid(archType) == false)
            {
                return null;
            }
            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("GetDismPath: Could not get the path to the WAIK utilities.");
                return null;
            }
            string toolArchitecture = GetWaikToolsArchitecture(archType);

            string toolPath = Path.Combine(waikPath, "Tools" + Path.DirectorySeparatorChar + toolArchitecture + Path.DirectorySeparatorChar + "Servicing" + Path.DirectorySeparatorChar + "dism.exe");
            if (File.Exists(toolPath))
            {
                WriteLog("GetDismPath: Found the dism.exe utility at : " + toolPath);
                return toolPath;    
            }
            WriteLog("GetDismPath: Could not find the dism.exe utility at : " + toolPath);
            return null; 
            
        }

        /// <summary>
        /// Locates the peimg.exe utility within the installed WAIK and returns the path.
        /// </summary>
        /// <returns>A string containing the full path and file name of the peimg.exe utility, or null if not found or on error.</returns>
        private string GetPeImgPath()
        {
            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("GetPeImgPath: Could not get the path to the WAIK utilities.");
                return null;
            }
            string toolPath = Path.Combine(waikPath, "Tools" + Path.DirectorySeparatorChar + "PETools" + Path.DirectorySeparatorChar + "peimg.exe");
            if (File.Exists(toolPath))
            {
                WriteLog("GetPeImgPath: Found the peimg.exe.exe utility at : " + toolPath);
                return toolPath;
            }
            WriteLog("GetPeImgPath: Could not find the peimg.exe utility at : " + toolPath);
            return null; 
            
        }

        /// <summary>
        /// Locates the installed WAIK and returns the path to the "Tools" directory within.
        /// </summary>
        /// <returns>A string containing the full path to the Tools directory in the WAIK, or null if not found or on error.</returns>
        private string GetWaikPath()
        {
            try
            {

                WriteLog("Getting the WAIK installation path");

                //' Read the registry key 
                //' HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ComponentStudio\<waik version>\ServicingPath 
                //' and get the WAIK installation path.

                //' Get the WMI object to access registry
                //Dim regKeyPath, allSubKeys, subKey, subKeyName
                bool try64bit = false;

                RegistryKey hklm = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\ComponentStudio");
                string keyPath = string.Empty;

                if (hklm != null)
                {
                    //WriteLog("Found the ComponentStudio key");

                    string[] subkeys = hklm.GetSubKeyNames();
                    if ((subkeys == null) || (subkeys.Length < 1))
                    {
                        WriteLog("GetWaikPath(): Failed to read the ComponentStudio subkeys");
                        try64bit = true;
                    }
                    else
                    {
                        WriteLog("Found the ComponentStudio subkeys: " + string.Concat(subkeys));

                        //' There should be only one sub key with the WAIK version number.
                        string key = string.Empty;
                        foreach (string keyname in subkeys)
                        {
                            key = keyname;
                            break;
                        }
                        WriteLog("Found the target key: " + key);

                        if (string.IsNullOrEmpty(key))
                        {
                            WriteLog("GetWaikPath(): Failed to read the registry key under ComponentStudio");
                            try64bit = true;
                        }
                        else
                        {
                            string fullKey = "HKEY_LOCAL_MACHINE\\Software\\Microsoft\\ComponentStudio\\" + key;

                            WriteLog("Looking for path in: " + fullKey);

                            keyPath = (string)Registry.GetValue(fullKey, "ServicingPath", null);

                            if (string.IsNullOrEmpty(keyPath))
                            {
                                WriteLog("GetWaikPath(): Failed to read the registry key");
                                try64bit = true;
                            }
                        }
                    }
                }
                else
                {
                    try64bit = true;
                }

                if (try64bit == true)
                {
                    WriteLog("GetWaikPath(): Failed to read the WAIK registry key. Trying 64-bit mode");
                    List<string> subkeys = new List<string>();

                    if (IntegrationKitUtilities.GetRegistrySubKeys(
                            IntegrationKitUtilities.HKLM, 
                            @"Software\Microsoft\ComponentStudio", 
                            true, 
                            out subkeys)
                            != 0)
                    {
                        WriteLog("GetWaikPath(): Failed to read the subkeys for HKLM\\Software\\Microsoft\\ComponentStudio");
                        return null;
                    }
                    if ((subkeys != null) && (subkeys.Count > 0))
                    {

                        string subkeyName = subkeys[subkeys.Count - 1];

                        if (string.IsNullOrEmpty(subkeyName))
                        {
                            WriteLog("GetWaikPath(): Subkey value was blank!");
                            return null;
                        }
                        WriteLog("GetWaikPath(): subkey[" + (subkeys.Count - 1) + "] = " + subkeyName);
                        WriteLog("GetWaikPath(): Now reading the value for \'ServicingPath\" from the subkey");

                        if (IntegrationKitUtilities.GetRegistryStringValue(
                            IntegrationKitUtilities.HKLM,
                            @"Software\Microsoft\ComponentStudio\" + subkeyName,
                            "ServicingPath",
                            true,
                            ref keyPath) != 0)
                        {
                            WriteLog("GetWaikPath(): Failed to read the \"ServicingPath\" value from the subkey \"HKLM\\Software\\Microsoft\\ComponentStudio\\" + subkeyName);
                            return null;
                        }
                    }
                    else
                    {
                        WriteLog("GetWaikPath(): Failed to read the keys value for " + keyPath);
                        return null;
                    }
                }

                if (string.IsNullOrEmpty(keyPath) == false)
                {
                    if (Directory.Exists(keyPath) == false)
                    {
                        WriteLog("GetWaikPath(): waikPath directory (" + keyPath + ") does not exist");
                        return null;
                    }

                    WriteLog("Found the servicing path: " + keyPath);
                    //' The reg value will be similar to C:\Program Files\Windows AIK\Tools\Servicing\.
                    //' We need to get the part C:\Program Files\Windows AIK\Tools out of this.

                    int pos = keyPath.LastIndexOf("\\Tools");
                    string basePath = keyPath.Substring(0, pos);

                    WriteLog("Path to WAIK tools: '" + basePath + "'");
                    WriteLog("WAIK version: " + GetWaikVersion().ToString());
                    return basePath;
                }

                WriteLog("GetWaikPath(): Failed to get the WAIK path");
                return null;
            }
            catch(Exception e)
            {
                WriteLog("Exception occurred in GetWaikPath():" + e.Data + "\n" + e.InnerException + "\n" + e.Message + "\n" + e.Source + "\n" + e.StackTrace  + "\n" + e.TargetSite);
                throw;
            }

        }

        /// <summary>
        /// Determines the version of the WAIK installed.
        /// </summary>
        /// <returns>A Version type containing the 4-part version of the WAIK, or null on any error or if not installed.</returns>
        private Version GetWaikVersion()
        {
            try
            {
                WriteLog("GetWaikVersion(): Starting...");

                //' Read the registry key 
                //' HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ComponentStudio\<waik version>
                bool try64bit = false;
                string subkeyName = string.Empty;
                
                RegistryKey hklm = Registry.LocalMachine.OpenSubKey("Software\\Microsoft\\ComponentStudio");
                string keyPath = string.Empty;

                if (hklm != null)
                {
                    string[] subkeys = hklm.GetSubKeyNames();
                    if ((subkeys == null) || (subkeys.Length < 1))
                    {
                        WriteLog("GetWaikVersion(): Failed to read the ComponentStudio subkeys");
                        try64bit = true;
                    }
                    else
                    {
                        WriteLog("GetWaikVersion(): Found the ComponentStudio subkeys: " + string.Concat(subkeys));

                        //' There should be only one sub key with the WAIK version number.
                        foreach (string keyname in subkeys)
                        {
                            subkeyName = keyname;
                            break;
                        }
                        WriteLog("GetWaikVersion(): Found the target key: " + subkeyName);

                        if (string.IsNullOrEmpty(subkeyName))
                        {
                            WriteLog("GetWaikVersion(): Failed to read the registry key under ComponentStudio");
                            try64bit = true;
                        }
                    }
                }
                else
                {
                    WriteLog("GetWaikVersion(): Failed to read the base ComponentStudio registry key");
                    try64bit = true;
                }


                if (try64bit == true)
                {
                    WriteLog("GetWaikVersion(): Failed to read the WAIK registry key. Trying 64-bit mode");
                    List<string> subkeys = new List<string>();

                    if (IntegrationKitUtilities.GetRegistrySubKeys(
                            IntegrationKitUtilities.HKLM,
                            @"Software\Microsoft\ComponentStudio",
                            true,
                            out subkeys)
                            != 0)
                    {
                        WriteLog("GetWaikVersion(): Failed to read the subkeys for HKLM\\Software\\Microsoft\\ComponentStudio");
                        return null;
                    }
                    if ((subkeys != null) && (subkeys.Count > 0))
                    {

                        subkeyName = subkeys[subkeys.Count - 1];

                        if (string.IsNullOrEmpty(subkeyName))
                        {
                            WriteLog("GetWaikVersion(): Subkey value was blank!");
                            return null;
                        }
                        WriteLog("GetWaikVersion(): subkey[" + (subkeys.Count - 1) + "] = " + subkeyName);

                        
                    }
                    else
                    {
                        WriteLog("GetWaikVersion(): Failed to read the keys value for " + keyPath);
                        return null;
                    }
                }

                if (string.IsNullOrEmpty(subkeyName))
                {
                    WriteLog("GetWaikVersion(): ERROR - Failed to read the registry key");
                    return null;
                }
                else
                {
                    WriteLog("GetWaikVersion(): WAIK version found: '" + subkeyName + "'");
                    Version ver = new Version(subkeyName);
                    
                    return ver;
                }
                
            }
            catch(Exception e)
            {
                WriteLog("Exception occurred in GetWaikVersion():" + e.StackTrace);
                throw;
            }
        }

        //private InstallerReturnValue MountWimFile(string wimFile, string mountPath)
        //{
        //    string waikPath = GetWaikPath();
        //    if (string.IsNullOrEmpty(waikPath))
        //    {
        //        WriteLog("GetWimInfo: Could not get the path to the WAIK utilities.");
        //        return InstallerReturnValue.Error;
        //    }
        //    if (Directory.Exists(waikPath) == false)
        //    {
        //        WriteLog("GetWimInfo: Path to the WAIK utilities does not exist.");
        //        return InstallerReturnValue.Error;
        //    }
        //    if (string.IsNullOrEmpty(wimFile))
        //    {
        //        throw new ArgumentNullException("wimFile");
        //    }
        //    if (File.Exists(wimFile) == false)
        //    {
        //        throw new ArgumentException(Properties.Resources.Error_InvalidParameter, "wimFile");
        //    }
        //    if (string.IsNullOrEmpty(mountPath))
        //    {
        //        throw new ArgumentNullException("mountPath");
        //    }

        //    if (Directory.Exists(mountPath) == false)
        //    {
        //        Directory.CreateDirectory(mountPath);
        //    }
        //    string cmdLine = string.Empty;
        //    int retVal = 0;

        //    cmdLine = Path.Combine(waikPath, "Tools\\x86\\imagex.exe");
        //    WriteLog("Running : " + cmdLine);
        //    if (File.Exists(cmdLine) == false)
        //    {
        //        WriteLog("Could not find the imagex.exe utility at : " + cmdLine);
        //        return InstallerReturnValue.Error;
        //    }

        //    string args = "/mountrw " + "\"" + wimFile + "\"" + " 1 " + "\"" + mountPath + "\"";
        //    string output = string.Empty;
        //    string workingDirectory = Path.Combine(waikPath, "Tools\\x86");
        //    int timeout = 60;

        //    WriteLog("argument string : " + args);


        //    retVal = RunCommandLine.RunExe(cmdLine, workingDirectory, args, timeout, out output);
        //    //LogStream(LogFile, output);
        //    //WriteLog(output);
        //    if (retVal != 0)
        //    {
        //        return InstallerReturnValue.Error;
        //    }

        //    return InstallerReturnValue.Success;

        //}

        //private InstallerReturnValue UnmountWimFile(string mountPath, bool commit)
        //{
        //    string waikPath = GetWaikPath();
        //    if (string.IsNullOrEmpty(waikPath))
        //    {
        //        WriteLog("GetWimInfo: Could not get the path to the WAIK utilities.");
        //        return InstallerReturnValue.Error;
        //    }
        //    //if (Directory.Exists(waikPath) == false)
        //    //{
        //    //    WriteLog("GetWimInfo: Path to the WAIK utilities does not exist.");
        //    //    return InstallerReturnValue.Error;
        //    //}
        //    if ((string.IsNullOrEmpty(mountPath)) ||
        //        (Directory.Exists(mountPath) == false))
        //    {
        //        throw new ArgumentNullException("mountPath");
        //    }

        //    string cmdLine = GetImagexPath();
        //    if (string.IsNullOrEmpty(cmdLine))
        //    {
        //        return InstallerReturnValue.Error;
        //    }

        //    WriteLog("Running : " + cmdLine);
        //    int retVal = 0;
        //    string args = string.Empty;
        //    if (commit)
        //    {
        //        args = "/unmount /commit " + "\"" + mountPath + "\"";
        //    }
        //    else
        //    {
        //        args = "/unmount " + "\"" + mountPath + "\"";
        //    }
        //    string output = string.Empty;
        //    string workingDirectory = GetFileParentDirectory(cmdLine);
        //    int timeout = 60;

        //    WriteLog("argument string : " + args);

        //    retVal = RunCommandLine.RunExe(cmdLine, workingDirectory, args, timeout, out output);
        //    //LogStream(LogFile, output);
        //    WriteLog(output);
        //    if (retVal != 0)
        //    {
        //        return InstallerReturnValue.Error;
        //    }

        //    return InstallerReturnValue.Success;

        //}

        /// <summary>
        /// Returns the relative or absolute directory structure of a file provided with directory information in a string.
        /// </summary>
        /// <param name="filePath">The path and filename of a file (file does not have to exist).</param>
        /// <returns>A string value containing the parent directory structure, or null on error or if the string does not contain any path information.</returns>
        private string GetFileParentDirectory(string filePath)
        {
            string path = string.Empty;
            FileInfo fi = new FileInfo(filePath);
            if (fi == null)
            {
                WriteLog("GetFileParentDirectory:  file specified does not currently exist. Trying to get directory name via string search");
                int pos = filePath.LastIndexOf("\\");
                if (pos == -1)
                {
                    WriteLog("GetFileParentDirectory:  file name specified does not contain a path structure. Can't find the parent directory.");
                    return null;
                }
                path = filePath.Substring(0, pos);
            }
            else
            {
                path = fi.DirectoryName;
            }
            return path;
        }

        /// <summary>
        /// Copies a single image within a WIM containing one or more images into a new file.
        /// </summary>
        /// <param name="src_file">The path and filename of the source WIM file.</param>
        /// <param name="dest_file">The path and filename of the new WIM file to be created.</param>
        /// <param name="imageIndex">The index of the image within the source file to be copied.</param>
        /// <returns>A return code indicating success or failure.</returns>
        private InstallerReturnValue ExportWimFile(string src_file, string dest_file, int imageIndex)
        {
            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("ExportWimFile: Could not get the path to the WAIK utilities.");
                return InstallerReturnValue.Error;
            }
            //if (Directory.Exists(waikPath) == false)
            //{
            //    WriteLog("GetWimInfo: Path to the WAIK utilities does not exist.");
            //    return InstallerReturnValue.Error;
            //}
            if ((string.IsNullOrEmpty(src_file)) || (File.Exists(src_file) == false))
            {
                WriteLog("ExportWimFile: source file parameter specified (" + src_file + ") was invalid.");
                return InstallerReturnValue.Error;
            }

            if (string.IsNullOrEmpty(dest_file))
            {
                WriteLog("ExportWimFile: destination file parameter specified (" + dest_file + ") was invalid.");
                return InstallerReturnValue.Error;
            }

            //if the destination file exists, it needs to be renamed
            if (File.Exists(dest_file))
            {
                if (MoveOldWimFile(dest_file, dest_file + ".old") != InstallerReturnValue.Success)
                {
                    WriteLog("ExportWimFile: Destination WIM file (" + dest_file + ")exists and an error occurred trying to rename it.");
                    return InstallerReturnValue.Error;
                }
            }
            if (imageIndex < 1)
            {
                WriteLog("ExportWimFile: image index parameter specified (" + imageIndex + ") was invalid.");
                return InstallerReturnValue.Error;
            }

            //  Command line syntax for 'imagex /export'
            //  src_file [src_number | src_name] dest_file dest_name /boot

            int retVal = 0;

            string cmdLine = GetImagexPath(GetWimArchitecture(src_file, imageIndex), waikPath);
            if (string.IsNullOrEmpty(cmdLine))
            {
                return InstallerReturnValue.Error;
            }
             
            //need to get the title of the image from the WIM (needed for the command line)
            XmlDocument xmlInfo = GetWimInfo(src_file);
            if (xmlInfo == null)
            {
                WriteLog("ExportWimFile: Could not get the info from the WIM file: " + src_file);
                return InstallerReturnValue.Error;
            }
            WriteLog("ExportWimFile: Getting the image name from the WIM file");
            XmlNode imageNode = IntegrationKitUtilities.GetXmlNode(xmlInfo, "//IMAGE[@INDEX='" + imageIndex + "']");
            if (imageNode == null)
            {
                WriteLog("ExportWimFile: Could not get the info for image from the WIM file: " + src_file);
                return InstallerReturnValue.Error;
            }

            string src_name = IntegrationKitUtilities.GetXmlNodeValue(imageNode, ".//NAME");

            WriteLog("ExportWimFile: Image name is: " + src_name);

            string dest_name = src_name;
            
            src_file = "\"" + src_file + "\"";
            src_name = "\"" + src_name + "\"";
            dest_name = "\"" + dest_name + "\"";
            dest_file = "\"" + dest_file + "\"";

            string args = "/export" + " " + src_file + " " + imageIndex + " " + dest_file + " " + dest_name + " " + "/boot";
            string output = string.Empty;
            string workingDirectory = GetFileParentDirectory(cmdLine);
            int timeout = 120;

            WriteLog("ExportWimFile: Running : " + cmdLine);
            WriteLog("ExportWimFile: argument string : " + args);
           
            retVal = RunCommandLine.RunExe(cmdLine, workingDirectory, args, timeout, out output);
            // //LogStream(LogFile, output);
            WriteLog(output);
            if (retVal != 0)
            {
                WriteLog("ExportWimFile: Error [" + retVal + "] occurred exporting the WIM file");
                return InstallerReturnValue.Error;
            }
            WriteLog("ExportWimFile: Successfully exported the WIM file");
            return InstallerReturnValue.Success;

        }
        
        /// <summary>
        /// Finds the full path and filename of the WinPE package specified in the installer XML for the given architecture.
        /// </summary>
        /// <param name="packageName">The string containing the package name as specified in the installer XML</param>
        /// <param name="archType">The architecture type of the image, which determines the directory structure of the package location.</param>
        /// <returns>The full path and filename of the package .cab file, or null on error.</returns>
        private string GetWaik3PackagePath(string packageName, string archType)
        {
            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("GetWaik3PackagePath: Could not get the path to the WAIK utilities.");
                return null;
            }
            if (string.IsNullOrEmpty(packageName))
            {
                WriteLog("GetWaik3PackagePath: package name was not specified!");
                return null;
            }
            if (IsWaikArchStringValid(archType) == false)
            {
                WriteLog("GetWaik3PackagePath: architecture type specified (" + archType + ") was not valid.");
                return null;
            }
            packageName = packageName.Replace("-Package", "");  //convert WAIK 2.x package names to WAIK 3 names
            packageName = packageName.Replace("WAIK30-", "");   //convert names used in schema doc to official package names

            string packageFile = Path.Combine(waikPath, "Tools" + Path.DirectorySeparatorChar + "PETools" + Path.DirectorySeparatorChar + archType + Path.DirectorySeparatorChar + "WinPE_FPs" + Path.DirectorySeparatorChar + packageName + ".cab");
            if (File.Exists(packageFile) == false)
            {
                WriteLog("GetWaik3PackagePath: Package file name specified (" + packageFile + ") could not be found!");
                return null;
            }
            return packageFile;
        }

        /// <summary>
        /// Installs a WinPE package into an image so that the functionality will be available at runtime.
        /// </summary>
        /// <param name="archType">The architecture type of the image (used to determine the correct utilities to use)</param>
        /// <param name="mountPath">The full path to the mounted image</param>
        /// <param name="packageName">The name of the package as specified in the installer XML</param>
        /// <returns>A return code indicating success or failure.</returns>
        private InstallerReturnValue InstallPackageToWinPe(string archType, string mountPath, string packageName)
        {
            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("InstallPackageToWinPe: Could not get the path to the WAIK utilities.");
                return InstallerReturnValue.Error;
            }
           
            if ((string.IsNullOrEmpty(mountPath)) ||
                (Directory.Exists(mountPath) == false))
            {
                WriteLog("InstallPackageToWinPe: mountPath directory (" + mountPath + ") does not exist");
                return InstallerReturnValue.InvalidParameter;
            }
            if (string.IsNullOrEmpty(packageName))
            {
                WriteLog("InstallPackageToWinPe: packageName parameter was invalid");
                return InstallerReturnValue.InvalidParameter;
            }


            int retVal = 0;

            //modified 6/16/09 by rhearn
            // - Added support for WAIK 3.0 utilities

            mountPath = "\"" + mountPath + "\"";
            
            Version waikVersion = GetWaikVersion();
            string cmdLine = string.Empty;
            string args = string.Empty;
            string workingDir = string.Empty;

            if ((waikVersion.Major == 6) && (waikVersion.Minor == 0))
            {
                if (packageName.Contains("WAIK30"))
                {
                    WriteLog("InstallPackageToWinPe: package specified (" + packageName + ") is not supported by this version of WAIK.");
                    return InstallerReturnValue.InvalidParameter;
                }

                cmdLine = GetPeImgPath();
                workingDir = GetFileParentDirectory(cmdLine);
                //modified 12/10/09 by rhearn
                // removed redundant quotes around mount path (already handled at line 5582)
                args = "/install=" + packageName + " " + mountPath;
            }
            else if ((waikVersion.Major == 6) && (waikVersion.Minor == 1))
            {
                //modified 11/3/09 by rhearn to fix bug #6135
                if (packageName.ToLowerInvariant().StartsWith("winpe-xml"))
                {
                    WriteLog("InstallPackageToWinPe: package specified (" + packageName + ") is pre-installed by this version of WAIK and reinstall will not be attempted.");
                    return InstallerReturnValue.Success;
                }
                cmdLine = GetDismPath(archType);
                workingDir = GetFileParentDirectory(cmdLine);
                string packageFile = GetWaik3PackagePath(packageName, archType);
                //string packageFile = Path.Combine(waikPath, "Tools" + Path.DirectorySeparatorChar + "PETools" + Path.DirectorySeparatorChar + arch + Path.DirectorySeparatorChar + "WinPE_OCs" + Path.DirectorySeparatorChar + packageName.Replace("-Package", ""));
                packageFile = "\"" + packageFile + "\"";

                args = "/image:" + mountPath + " /Add-Package /PackagePath:" + packageFile;
            }
            else
            {
                WriteLog("WAIK version is not supported");
                //UnMountWimFile(mountPath, false);
                return InstallerReturnValue.Error;
            }


            if (File.Exists(cmdLine) == false)
            {
                WriteLog("InstallPackageToWinPe: Could not find the WAIK utility at : " + cmdLine);
                //UnMountWimFile(mountPath, false);
                return InstallerReturnValue.Error;
            }
                        
            string output = string.Empty;
            //string workingDirectory = Path.Combine(waikPath, "Tools" + Path.DirectorySeparatorChar + "PETools");
            int timeout = 60;

            WriteLog("argument string : " + args);
            //workingDir = "\"" + workingDir + "\"";

            retVal = RunCommandLine.RunExe(cmdLine, workingDir, args, timeout, out output);
            //LogStream(LogFile, output);
            WriteLog(output);
            WriteLog("InstallPackageToWinPe: Return value from running the command line = " + retVal);
            if (retVal != 0)
            {
                //UnMountWimFile(mountPath, false);
                return InstallerReturnValue.Error;
            }
            
            return InstallerReturnValue.Success;

        }

        //private InstallerReturnValue UninstallPackageToWinPe(string wimFile, string mountPath, string packageName)
        //{
        //    string waikPath = GetWaikPath();
        //    if (string.IsNullOrEmpty(waikPath))
        //    {
        //        WriteLog("UninstallPackageToWinPe: Could not get the path to the WAIK utilities.");
        //        return InstallerReturnValue.Error;
        //    }
        //    if (Directory.Exists(waikPath) == false)
        //    {
        //        WriteLog("UninstallPackageToWinPe: Path to the WAIK utilities does not exist.");
        //        return InstallerReturnValue.Error;
        //    }
        //    if (string.IsNullOrEmpty(wimFile))
        //    {
        //        WriteLog("UninstallPackageToWinPe: wimFile parameter was null or empty");
        //        return InstallerReturnValue.InvalidParameter;
        //    }
        //    if (File.Exists(wimFile) == false)
        //    {
        //        WriteLog("UninstallPackageToWinPe: wimFile (" + wimFile + ") does not exist");
        //        return InstallerReturnValue.InvalidParameter;
        //    }
        //    if ((string.IsNullOrEmpty(mountPath)) ||
        //        (Directory.Exists(mountPath) == false))
        //    {
        //        WriteLog("UninstallPackageToWinPe: mountPath directory (" + mountPath + ") does not exist");
        //        return InstallerReturnValue.InvalidParameter;
        //    }
        //    if (string.IsNullOrEmpty(packageName))
        //    {
        //        WriteLog("UninstallPackageToWinPe: packageName parameter was invalid");
        //        return InstallerReturnValue.InvalidParameter;
        //    }


        //    string cmdLine = string.Empty;
        //    int retVal = 0;

        //    cmdLine = Path.Combine(waikPath, "Tools" + Path.DirectorySeparatorChar + "PETools" + Path.DirectorySeparatorChar + "peimg.exe");
        //    WriteLog("Running : " + cmdLine);
        //    if (File.Exists(cmdLine) == false)
        //    {
        //        WriteLog("UninstallPackageToWinPe: Could not find the peimg.exe utility at : " + cmdLine);
        //        return InstallerReturnValue.Error;
        //    }
        //    string args = string.Empty;
        //    args = "/uninstall=" + packageName + " \"" + mountPath + "\"";
        //    string output = string.Empty;
        //    string workingDirectory = Path.Combine(waikPath, "Tools" + Path.DirectorySeparatorChar + "PETools");
        //    int timeout = 60;

        //    WriteLog("UninstallPackageToWinPe: argument string : " + args);

        //    retVal = RunCommandLine.RunExe(cmdLine, workingDirectory, args, timeout, out output);
        //    //LogStream(LogFile, output);
        //    //  WriteLog(output, true);
        //    WriteLog("UninstallPackageToWinPe: Return value from running the command line = " + retVal);
        //    if (retVal != 0)
        //    {
        //        return InstallerReturnValue.Error;
        //    }

        //    return InstallerReturnValue.Success;

        //}

        //private InstallerReturnValue ImportPackageToWinPe(string wimFile, string mountPath, string packagePath)
        //{
        //    string waikPath = GetWaikPath();
        //    if (string.IsNullOrEmpty(waikPath))
        //    {
        //        WriteLog("ImportPackageToWinPe: Could not get the path to the WAIK utilities.");
        //        return InstallerReturnValue.Error;
        //    }
        //    //if (Directory.Exists(waikPath) == false)
        //    //{
        //    //    WriteLog("GetWimInfo: Path to the WAIK utilities does not exist.");
        //    //    return InstallerReturnValue.Error;
        //    //}
        //    if (string.IsNullOrEmpty(wimFile))
        //    {
        //        WriteLog("ImportPackageToWinPe: wimFile parameter was null or empty");
        //        return InstallerReturnValue.InvalidParameter;
        //    }
        //    if (File.Exists(wimFile) == false)
        //    {
        //        WriteLog("ImportPackageToWinPe: wimFile (" + wimFile + ") does not exist");
        //        return InstallerReturnValue.InvalidParameter;
        //    }
        //    if ((string.IsNullOrEmpty(mountPath)) ||
        //        (Directory.Exists(mountPath) == false))
        //    {
        //        WriteLog("ImportPackageToWinPe: mountPath directory (" + mountPath + ") does not exist");
        //        return InstallerReturnValue.InvalidParameter;
        //    }
        //    if (string.IsNullOrEmpty(packagePath))
        //    {
        //        WriteLog("ImportPackageToWinPe: packagePath parameter was null or empty");
        //        return InstallerReturnValue.InvalidParameter;
        //    }

        //    //modified 6/16/09 by rhearn
        //    // - Added support for WAIK 3.0 utilities: 
        //    // -  WAIK 3.0 does not require import prior to installation of packages, so if WAIK 3.0, import is skipped

        //    Version waikVersion = GetWaikVersion();
        //    string cmdLine = string.Empty;
        //    string args = string.Empty;
        //    string workingDir = string.Empty;

        //    if ((waikVersion.Major == 6) && (waikVersion.Minor == 0))
        //    {
        //        cmdLine = GetPeImgPath();
        //        workingDir = GetFileParentDirectory(cmdLine);
        //        args = "/import=\"" + packagePath + "\" \"" + mountPath + "\"";

        //        int retVal = 0;

        //        WriteLog("ImportPackageToWinPe: Running : " + cmdLine);
        //        string output = string.Empty;
        //        int timeout = 60;

        //        WriteLog("argument string : " + args);

        //        retVal = RunCommandLine.RunExe(cmdLine, workingDir, args, timeout, out output);
        //        //LogStream(LogFile, output);
        //        // WriteLog(output, true);
        //        WriteLog("ImportPackageToWinPe: Return value from running the command line = " + retVal);
        //        if (retVal != 0)
        //        {
        //            return InstallerReturnValue.Error;
        //        }

        //    }
        //    else if ((waikVersion.Major == 6) && (waikVersion.Minor == 1))
        //    {
        //        return InstallPackageToWinPe(wimFile, mountPath, packagePath);
        //    }
        //    else
        //    {
        //        WriteLog("ImportPackageToWinPe: WAIK version is not supported");
        //        //UnMountWimFile(mountPath, false);
        //        return InstallerReturnValue.Error;
        //    }
        //    return InstallerReturnValue.Error;
        //}

        /// <summary>
        /// Modifies the default WinPE scratch space (size of the RAM disk used by WinPE) to the size provided.
        /// This overload sets the default architecture type to "x86".
        /// </summary>
        /// <param name="mountPath">The path to the mounted WinPE image</param>
        /// <param name="scratchSize">The new size (in MB) of the scratch space (must be one of 32, 64, 128, 256 or 512)</param>
        /// <returns>A return code indicating success or failure</returns>
        private InstallerReturnValue ChangeWinPeScratchSpace(string mountPath, string scratchSize)
        {
            return ChangeWinPeScratchSpace(mountPath, scratchSize, "x86");
        }
        
        /// <summary>
        /// Modifies the default WinPE scratch space (size of the RAM disk used by WinPE) to the size provided.
        /// </summary>
        /// <param name="mountPath">The path to the mounted WinPE image</param>
        /// <param name="scratchSize">The new size (in MB) of the scratch space (must be one of 32, 64, 128, 256 or 512)</param>
        /// <param name="archType">The CPU architecture type of the image (used to determine the proper WAIK utility to use)</param>
        /// <returns>A return code indicating success or failure</returns>
        private InstallerReturnValue ChangeWinPeScratchSpace(string mountPath, string scratchSize, string archType)
        {
            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("ChangeWinPeScratchSpace: Could not get the path to the WAIK utilities.");
                return InstallerReturnValue.Error;
            }
            //if (Directory.Exists(waikPath) == false)
            //{
            //    WriteLog("ChangeWinPeScratchSpace: Path to the WAIK utilities does not exist.");
            //    return InstallerReturnValue.Error;
            //}
            if (string.IsNullOrEmpty(scratchSize))
            {
                WriteLog("ChangeWinPeScratchSpace: scratchSize parameter was null");
                return InstallerReturnValue.InvalidParameter;
            }
            if ((string.IsNullOrEmpty(mountPath)) ||
                (Directory.Exists(mountPath) == false))
            {
                WriteLog("ChangeWinPeScratchSpace: mountPath directory (" + mountPath + ") does not exist");
                return InstallerReturnValue.InvalidParameter;
            }

            if (IsWaikArchStringValid(archType) == false)
            {
                WriteLog("ChangeWinPeScratchSpace: Architecture type specified (" + archType + ") was invalid.");
                return InstallerReturnValue.InvalidParameter;
            }

            if ((string.Compare(scratchSize, "32") == 0) ||
                (string.Compare(scratchSize, "64") == 0) ||
                (string.Compare(scratchSize, "128") == 0) ||
                (string.Compare(scratchSize, "256") == 0) ||
                (string.Compare(scratchSize, "512") == 0))
            {
                WriteLog("Scratchspace size " + scratchSize + " is valid");
            }
            else
            {
                WriteLog("Scratchspace size " + scratchSize + " was invalid");
                return InstallerReturnValue.InvalidParameter;
            }

            //modified 6/16/09 by rhearn
            // - Added support for WAIK 3.0 utilities
            mountPath = "\"" + mountPath + "\"";

            Version waikVersion = GetWaikVersion();
            string cmdLine = string.Empty;
            string args = string.Empty;
            string workingDir = string.Empty;

            if ((waikVersion.Major == 6) && (waikVersion.Minor == 0))
            {
                // - The scratchspace parameter is not supported by PEIMG.EXE prior to Vista SP1.
                // - These changes ensure that the minimum WAIK version is installed prior to running the command.
                // - Added the below IF statement to check this.
                Version targetWaikVer = new Version("6.0.6001.18000");
                if (waikVersion.CompareTo(targetWaikVer) < 0)
                {
                    WriteLog("ChangeWinPeScratchSpace: Current WAIK version is " + waikVersion.ToString() + " but is required to be at least " + targetWaikVer.ToString() + ". Not setting scratchspace.");
                    return InstallerReturnValue.Error;
                }
                cmdLine = GetPeImgPath();
                workingDir = GetFileParentDirectory(cmdLine);
                //modified 12/10/09 by rhearn
                // removed redundant quotes around mount path (already handled at line 5869)
                args = "/scratchspace=" + scratchSize + " " + mountPath;
            }
            else if ((waikVersion.Major == 6) && (waikVersion.Minor == 1))
            {
                cmdLine = GetDismPath(archType);
                workingDir = GetFileParentDirectory(cmdLine);
                args = "/image:" + mountPath + " /Set-ScratchSpace:" + scratchSize;
            }
            else
            {
                WriteLog("ChangeWinPeScratchSpace: WAIK version is not supported");
                //UnMountWimFile(mountPath, false);
                return InstallerReturnValue.Error;
            }
            
            int retVal = 0;
            string output = string.Empty;
            int timeout = 60;
            WriteLog("ChangeWinPeScratchSpace: Running command line : " + cmdLine);
            WriteLog("argument string : " + args);

            //workingDir = "\"" + workingDir + "\"";

            retVal = RunCommandLine.RunExe(cmdLine, workingDir, args, timeout, out output);
            //LogStream(LogFile, output);
            WriteLog(output);
            WriteLog("ChangeWinPeScratchSpace: Return value from running the command line = " + retVal);
            if (retVal != 0)
            {
                return InstallerReturnValue.Error;
            }

            return InstallerReturnValue.Success;

        }

        /// <summary>
        /// Performs a "Prep" command on a WinPE image to make it deployable. Required by Configuration Manager prior to import.
        /// Only required for WAIK version prior to WAIK 3.0.
        /// </summary>
        /// <param name="mountPath">The path to the mounted WIM image</param>
        /// <returns>A return value indicating success or failure.</returns>
        private InstallerReturnValue PrepWinPeImage(string mountPath)
        {
            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("PrepWinPeImage: Could not get the path to the WAIK utilities.");
                return InstallerReturnValue.Error;
            }
            
            if ((string.IsNullOrEmpty(mountPath)) ||
                (Directory.Exists(mountPath) == false))
            {
                WriteLog("PrepWinPeImage: mountPath directory (" + mountPath + ") does not exist");
                return InstallerReturnValue.InvalidParameter;
            }
            int retVal = 0;

            //modified 6/16/09 by rhearn
            // - Added changes for WAIK 3.0 utilities (prep no longer needed in WAIK 3.0)

            Version waikVersion = GetWaikVersion();
            string cmdLine = string.Empty;
            string args = string.Empty;
            string workingDir = string.Empty;

            if ((waikVersion.Major == 6) && (waikVersion.Minor == 0))
            {
                cmdLine = GetPeImgPath();
                workingDir = GetFileParentDirectory(cmdLine);
                args = "/prep /f \"" + mountPath + "\"";
            
            }
            else if ((waikVersion.Major == 6) && (waikVersion.Minor == 1))
            {
                // WAIK 3.0 does not require "prep" of an image
                return InstallerReturnValue.Success;
            }
            else
            {
                WriteLog("PrepWinPeImage: WAIK version is not supported");
                //UnMountWimFile(mountPath, false);
                return InstallerReturnValue.Error;
            }

            WriteLog("PrepWinPeImage: Running : " + cmdLine);
            string output = string.Empty;
            int timeout = 90;

            WriteLog("argument string : " + args);

            retVal = RunCommandLine.RunExe(cmdLine, workingDir, args, timeout, out output);
            //LogStream(LogFile, output);
            WriteLog(output);
        
            if (retVal == 2)
            {
                WriteLog("PrepWinPeImage: This WinPE image has already run the 'Prep' process. Continuing...");
            }
            else if (retVal != 0)
            {
                WriteLog("PrepWinPeImage: Error [" + retVal + "] occurred running the command line");
                return InstallerReturnValue.Error;
            }
        
            else
            {
                WriteLog("PrepWinPeImage: Successfully ran 'prep' on the WinPE image");
            }
            return InstallerReturnValue.Success;

        }


        private XmlDocument GetWimInfo(string wimFile)
        {
            return GetWimInfo(wimFile, "x86");
        }

        /// <summary>
        /// Reads and returns the XML info from the WIM file specified.
        /// </summary>
        /// <param name="wimFile">Path to the .WIM file to open.</param>
        /// <returns>An XmlDocument object containing the XML information, or null on any error.</returns>
        private XmlDocument GetWimInfo(string wimFile, string architecture)
        {
            WriteLog("GetWimInfo(): starting...");

            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("GetWimInfo: Could not get the path to the WAIK utilities.");
                return null;
            }
            //if (Directory.Exists(waikPath) == false)
            //{
            //    WriteLog("GetWimInfo: Path to the WAIK utilities does not exist.");
            //    return null;
            //}
            if (string.IsNullOrEmpty(wimFile))
            {
                WriteLog("GetWimInfo: wimFile parameter was null");
                return null;
            }
            if (File.Exists(wimFile) == false)
            {
                WriteLog("GetWimInfo: Path to the WAIK utilities does not exist.");
                return null;
            }
            if (IsWaikArchStringValid(architecture) == false)
            {
                WriteLog("GetWimArchitecture: Value of architecture parameter was invalid. Using 'x86' by default.");
                architecture = "x86";
               
            }

            string cmdLine = GetImagexPath(IntegrationKitUtilities.GetCPUArchitecture(), waikPath);
            if (string.IsNullOrEmpty(cmdLine))
            {
                return null;
            } 
            int retVal = 0;


            string workingDirectory = GetFileParentDirectory(cmdLine);
            string args = string.Empty;
            args = "/info \"" + wimFile + "\"";

            XmlDocument xmlInfo = new XmlDocument();
            string xmlString = string.Empty;
            string output = string.Empty;
            int timeout = 30;

            WriteLog("Running : " + cmdLine);
            WriteLog("argument string : " + args);

            retVal = RunCommandLine.RunExe(cmdLine, workingDirectory, args, timeout, out output);
            //LogStream(LogFile, output);
            //WriteLog(output, true);
            WriteLog("GetWimInfo: Return value from running the command line = " + retVal);

            if (retVal == 0)
            {
                bool writeThisLine = false;
                string[] outputLines = output.Split(new char[] { '\n' });
                foreach (string outputLine in outputLines)
                {
                    if (outputLine.Contains("<WIM>"))
                    {
                        writeThisLine = true;
                    }
                    if (writeThisLine == true)
                    {
                        xmlString += outputLine.Trim();
                    }
                    if (outputLine.Contains("</WIM>"))
                    {
                        break;
                    }
                }
                WriteLog("GetWimInfo: Output XML from WIM file: \n" + xmlString);
                //now try to load the XML output string into the XML document.
                try
                {
                    xmlInfo.LoadXml(xmlString);
                }
                catch (Exception e)
                {
                    WriteLog("GetWimInfo: Exception occurred trying to load the XML string into the XmlDocument./n" + e.Message);
                    //LogException(LogFile, e);
                    return null;
                }
                return xmlInfo;
            }
            else
            {
                return null;
            }


        }

        /// <summary>
        /// Reads the XML info from the WIM file specified and returns the CPU architecture of the image at the specified index.
        /// Converts 0, 6 and 9 architecture types to x86, ia64, and amd64, respectively.
        /// </summary>
        /// <param name="wimFile">Path to the .WIM file to open.</param>
        /// <param name="index">The index of the image within the WIM to examine.</param>
        /// <returns>A string value of the architecture type ("x86", "amd64" or "ia64")</returns>
        private string GetWimArchitecture(string wimFile, int index)
        {
            if (string.IsNullOrEmpty(wimFile))
            {
                WriteLog("GetWimArchitecture: wimFile parameter was null or empty");
                return null;
            }
            XmlDocument wimInfo = GetWimInfo(wimFile);
            if (wimInfo == null)
            {
                WriteLog("GetWimArchitecture: Could not get XML info from WIM file");
                return null;
            }

            if (index == 0)
            {
                index = 1;
            }
            XmlNode archNode = IntegrationKitUtilities.GetXmlNode(wimInfo, "//IMAGE[@INDEX='" + index + "']/WINDOWS/ARCH");
            if (archNode == null)
            {
                WriteLog("GetWimArchitecture: Could not get architecture for image with an index of [" + index + "]");
                return null;
            }
            string arch = IntegrationKitUtilities.GetXmlNodeValue(archNode, ".");
            if (string.IsNullOrEmpty(arch))
            {
                WriteLog("GetWimArchitecture: Could not get the value within the 'ARCH' node of the image");
                return null;
            }
            switch (arch)
            {
                case "0":
                    WriteLog("GetWimArchitecture: ARCH = 0. Converting to 'x86'"); 
                    arch = "x86";
                    break;

                case "9":
                    WriteLog("GetWimArchitecture: ARCH = 9. Converting to 'amd64'");
                    arch = "amd64"; 
                    break;

                case "6":
                    WriteLog("GetWimArchitecture: ARCH = 6. Converting to 'ia64'");
                    arch = "ia64"; 
                    break;

                default:
                    WriteLog("GetWimArchitecture: ARCH = '" + arch + "'. This is an invalid value."); 
                    arch = null;
                    break;
            }

            return arch;
        }        

        /// <summary>
        /// Provides a quick evaluation method for determining if the image inside a WIM file is Windows 7 / Server 2008 R2 or higher.
        /// This check is valuable in determining WAIK version compatibility with the image.
        /// </summary>
        /// <param name="wimFile">Path to the .WIM file to open.</param>
        /// <param name="index">The index of the image within the WIM to examine.</param>
        /// <returns>True if the image is Win7 or higher, false otherwise or on error.</returns>
        private bool IsWin7Wim(string wimFile, int index)
        {
            if (File.Exists(wimFile) == false)
            {
                WriteLog("GetWimVersion: WIM file specified (" + wimFile + ") is invalid.");
                return false;
            }

            if (index < 1)
            {
                WriteLog("GetWimVersion: image index specified was < 1 (value specified = " + index + ").");
                return false;
            }

            Version wimVersion = GetWimVersion(wimFile, index);
            if (wimVersion != null)
            {
                if ((wimVersion.Major == 6) && (wimVersion.Minor == 1))
                {
                    WriteLog("GetWimVersion: image index specified is a Win7 image (version " + wimVersion.ToString() + ")");
                    return true;
                }
            }
            WriteLog("GetWimVersion: image index specified is a not Win7 image (version " + wimVersion.ToString() + ")");
                      
            return false;
        }

        /// <summary>
        /// Reads the XML info from the WIM file specified and returns the version of the image at the specified index.
        /// This overload specifies a default image index of 1.
        /// </summary>
        /// <param name="wimFile">Path to the .WIM file to open.</param>
        /// <returns>A Version type containing the 4-part version information found, or null on any error.</returns>
        private Version GetWimVersion(string wimFile)
        {
            return GetWimVersion(wimFile, 1);
        }

        /// <summary>
        /// Reads the XML info from the WIM file specified and returns the version of the image at the specified index.
        /// </summary>
        /// <param name="wimFile">Path to the .WIM file to open.</param>
        /// <param name="index">The index of the image within the WIM to examine.</param>
        /// <returns>A Version type containing the 4-part version information found, or null on any error.</returns>
        private Version GetWimVersion(string wimFile, int index)
        {
            //string waikPath = GetWaikPath();
            //if (string.IsNullOrEmpty(waikPath))
            //{
            //    WriteLog("GetWimVersion: Could not get the path to the WAIK utilities.");
            //    return null;
            //}
            if (File.Exists(wimFile) == false)
            {
                WriteLog("GetWimVersion: WIM file specified (" + wimFile + ") is invalid.");
                return null;
            }

            if (index < 1)
            {
                WriteLog("GetWimVersion: image index specified was < 1 (value specified = " + index + ").");
                return null;
            }

            XmlDocument xmlInfo = GetWimInfo(wimFile);
            if (xmlInfo == null)
            {
                WriteLog("GetWimVersion: Could not get the info from the WIM file: " + wimFile);
                return null;
            }

            XmlNode imageNode = IntegrationKitUtilities.GetXmlNode(xmlInfo, "//IMAGE[@INDEX='" + index + "']");
            if (imageNode == null)
            {
                WriteLog("GetWimVersion: Could not find information for image index " + index);
                return null;
            }
            string majVersion = IntegrationKitUtilities.GetXmlNodeValue(imageNode, ".//VERSION/MAJOR");
            string minVersion = IntegrationKitUtilities.GetXmlNodeValue(imageNode, ".//VERSION/MINOR");
            string buildNumber = IntegrationKitUtilities.GetXmlNodeValue(imageNode, ".//VERSION/BUILD");
            string spBuild = IntegrationKitUtilities.GetXmlNodeValue(imageNode, ".//VERSION/SPBUILD");


            int output = 0;


            if (int.TryParse(majVersion, out output) == false)
            {
                majVersion = "0";
            }
            if (int.TryParse(minVersion, out output) == false)
            {
                minVersion = "0";
            }
            if (int.TryParse(buildNumber, out output) == false)
            {
                buildNumber = "0";
            }
            if (int.TryParse(spBuild, out output) == false)
            {
                spBuild = "0";
            }

            Version ver = new Version(majVersion + "." + minVersion + "." + buildNumber + "." + spBuild);
            return ver;

        }

        /// <summary>
        /// Finds the Windows System directory name specified in the "SYSTEMROOT" element of the WIM info XML. 
        /// This is equivalent to the "WinDir" system environment variable, except only the directory name (not full path) is specified.
        /// Typically, the value of this element is "WINDOWS". This overload specifies a default image index of 1.
        /// </summary>
        /// <param name="wimFile">Path to the .WIM file to open.</param>
        /// <returns>A string value of the directory name, or null if any error occurs.</returns>
        private string GetWimSystemRoot(string wimFile)
        {
            return GetWimSystemRoot(wimFile, 1);
        }

        /// <summary>
        /// Finds the Windows System directory name specified in the "SYSTEMROOT" element of the WIM info XML. 
        /// This is equivalent to the "WinDir" system environment variable, except only the directory name (not full path) is specified.
        /// Typically, the value of this element is "WINDOWS"
        /// </summary>
        /// <param name="wimFile">Path to the .WIM file to open.</param>
        /// <param name="index">The index of the image within the WIM to examine.</param>
        /// <returns>A string value of the directory name, or null if any error occurs.</returns>
        private string GetWimSystemRoot(string wimFile, int index)
        {
            WriteLog("GetWimSystemRoot(): starting...");

            string waikPath = GetWaikPath();
            if (string.IsNullOrEmpty(waikPath))
            {
                WriteLog("GetWimSystemRoot: Could not get the path to the WAIK utilities.");
                return null;
            }
            //if (Directory.Exists(waikPath) == false)
            //{
            //    WriteLog("GetWimSystemRoot: Path to the WAIK utilities does not exist.");
            //    return null;
            //}
            
            if (string.IsNullOrEmpty(wimFile))
            {
                WriteLog("GetWimSystemRoot: wimFile parameter was null");
                return null;
            }
            if (File.Exists(wimFile) == false)
            {
                WriteLog("GetWimSystemRoot: Path to the WIM file does not exist.");
                return null;
            }
            if (index < 1)
            {
                WriteLog("GetWimSystemRoot: image index specified was < 1 (value specified = " + index + ").");
                return null;
            }

            XmlDocument xmlInfo = GetWimInfo(wimFile);
            if (xmlInfo == null)
            {
                WriteLog("GetWimSystemRoot: Could not get XML info from WIM file!");
                return null;
            }

            XmlNode imageNode = IntegrationKitUtilities.GetXmlNode(xmlInfo, "//IMAGE[@INDEX='" + index + "']");
            if (imageNode == null)
            {
                WriteLog("GetWimSystemRoot: Could not get the IMAGE (index=" + index + ") node from the WIM file XML info output!");
                return null;
            }

            string winDir = IntegrationKitUtilities.GetXmlNodeValue(imageNode, ".//SYSTEMROOT");
            if (string.IsNullOrEmpty(winDir))
            {
                WriteLog("GetWimSystemRoot: SYSTEMROOT was empty in WIM file XML info!");
                return null;
            }

            return winDir;


        }


        #endregion



        private DirectoryInfo GetExtensionsDir(XmlNode node)
        {
            //WriteLog("Now in GetCustomActionDir()"); 
            if (IntegrationKitUtilities.IsValidXmlElement(node) == false)
            {
                if (node.NodeType == XmlNodeType.Comment)
                {
                    //WriteLog("Node was a comment - skipping.");
                    return null;
                }
                WriteLog("node parameter passed in to ProcessCustomAction was not a valid XML element. Cannot continue.");
                return null;
            }
            //get the SCCM local install directory and add AdminUI\XmlStorage\Extensions
            string baseDir = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Setup", "UI Installation Directory");
            if (string.IsNullOrEmpty(baseDir))
            {
                baseDir = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Installation Directory");
                if (string.IsNullOrEmpty(baseDir))
                {
                    WriteLog("Error! ConfigMgr Local Install Dir property value was not found in the registry.");
                    return null;
                }
                else
                {
                    baseDir += "\\AdminUI\\XmlStorage\\Extensions\\";
                }
            }
            else
            {
                baseDir += "\\XmlStorage\\Extensions\\";
            }
            //test the baseDir to make sure it exists - it should be default
            if (Directory.Exists(baseDir) == false)
            {
                WriteLog("Error! Could not find base Extensions directory at: " + baseDir);
                return null;
            }
            else
            {
                DirectoryInfo theDir = new DirectoryInfo(baseDir);
                return theDir;
            }
        }

        private DirectoryInfo CreateCustomActionDir(XmlNode node)
        {
            //WriteLog("Now in CreateCustomActionDir()"); 
            if (IntegrationKitUtilities.IsValidXmlElement(node) == false)
            {
                if (node.NodeType == XmlNodeType.Comment)
                {
                    //WriteLog("Node was a comment - skipping.");
                    return null;
                }
                WriteLog("node parameter passed in to CreateCustomActionDir was not a valid XML element. Cannot continue.");
                return null;
            }
            DirectoryInfo extensionsDir = GetExtensionsDir(node);
            if (extensionsDir == null)
            {
                WriteLog("Error! Could not get the path to the Extensions directory.");
                return null;
            }

            //get the SCCM local install directory and add AdminUI\XmlStorage\Extensions
            string baseDir = extensionsDir.FullName + "Actions\\";

            //test the baseDir to make sure it exists - it should be default
            if (Directory.Exists(baseDir) == false)
            {
                DirectoryInfo actionsDir = Directory.CreateDirectory(baseDir);
                if (actionsDir == null)
                {
                    WriteLog("Error! Could not find base Extensions directory at: " + baseDir);
                    return null;
                }
            }

            //check to see if a directory exists for the node guid. If not, create it.
            DirectoryInfo newDir = null;
            string nodeGuid = IntegrationKitUtilities.GetXmlNodeValue(node, ".//NodeGuid");
            if (Directory.Exists(baseDir + nodeGuid) == false)
            {
                try
                {
                    newDir = Directory.CreateDirectory(baseDir + nodeGuid);
                }
                catch (Exception ex)
                {
                    WriteLog("Exception occurred while trying to create the custom action directory: " + baseDir + nodeGuid + "\n" + ex.Data);
                    return null;
                }
            }
            else
            {
                //directory already exists. Setup newDir with the info
                newDir = new DirectoryInfo(baseDir + nodeGuid);
            }
            return newDir;
        }

        private DirectoryInfo GetCustomActionDir(XmlNode node)
        {
            if (IntegrationKitUtilities.IsValidXmlElement(node) == false)
            {
                if (node.NodeType == XmlNodeType.Comment)
                {
                    //WriteLog("Node was a comment - skipping.");
                    return null;
                }
                WriteLog("node parameter passed in to GetCustomActionDir was not a valid XML element. Cannot continue.");
                return null;
            }
            DirectoryInfo extensionsDir = GetExtensionsDir(node);
            if (extensionsDir == null)
            {
                WriteLog("Error! Could not get the path to the Extensions directory.");
                return null;
            }

            DirectoryInfo newDir = null;
            //get the SCCM local install directory and add AdminUI\XmlStorage\Extensions\Actions\{node guid}
            string nodeGuid = IntegrationKitUtilities.GetXmlNodeValue(node, ".//NodeGuid");
            
            string baseDir = extensionsDir.FullName + "Actions\\" + nodeGuid;
            
            //check to see if a directory exists for the node guid. If not, return a null.
            if (Directory.Exists(baseDir) == false)
            {
                WriteLog("Custom action directory not found : " + baseDir);
                return null;
            }
            else
            {
                //directory already exists. Setup newDir with the info
                newDir = new DirectoryInfo(baseDir);
            }
            return newDir;
        }

        private InstallerReturnValue AddCustomActionMenu(XmlNode node)
        {
            if (node == null)
            {
                WriteLog("Xml node passed in to AddCustomActionMenu was null. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }

            //Get the list of nodes where this will be applied. Each node contains NodeGuid and FileName child elements
            XmlNodeList actionNodes = IntegrationKitUtilities.GetXmlNodeList(node, ".//ActionXmlInfo/Nodes");
            if (actionNodes == null)
            {
                WriteLog("Custom action XML did not contain info about the custom action nodes (ActionXmlInfo). Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }

            //Now, for each child node, create a new file or update an existing file with the XML contents
            foreach (XmlNode actionNode in actionNodes)
            {
                //get the contents of the XML file
                XmlNode actionContentXml = IntegrationKitUtilities.GetXmlNode(node, ".//ActionXmlContent/ActionDescription");
                if (actionContentXml == null)
                {
                    WriteLog("Custom action XML did not contain info about the custom action XML file (ActionXmlContent). Cannot continue.");
                    return InstallerReturnValue.Error;
                }

                DirectoryInfo baseDir = CreateCustomActionDir(actionNode);
                if (baseDir == null)
                {
                    WriteLog("Could not create the custom action directory. Cannot continue.");
                    return InstallerReturnValue.Error;
                }

                //get the XML node and filename info
                string actionXmlFile = IntegrationKitUtilities.GetXmlNodeValue(node, ".//FileName");
                if (string.IsNullOrEmpty(actionXmlFile))
                {
                    WriteLog("File name for new custom action XML file not found. Cannot continue.");
                    return InstallerReturnValue.Error;
                } 
                //check to see if the file exists
                string fileName = baseDir.FullName + "\\" + actionXmlFile;
                if (File.Exists(fileName) == false)
                {
                    WriteLog("Custom action menu XML file (" + fileName + ") does not exist. Creating a new file");
                    
                    //file doesn't exist. create it.
                    string content = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" + actionContentXml.OuterXml.ToString();
                    if (IntegrationKitUtilities.ExportTextFileNoDialog(fileName, content) == false)
                    {
                        WriteLog("Could not create the custom action form XML file (" + fileName + "). Cannot continue.");
                        return InstallerReturnValue.Error;
                    }
                }
                else
                {
                    //the file already exists. Open it and add the necessary XML (if it doesn't already exit)
                    WriteLog("Custom action menu XML file (" + fileName + ") found. Checking current contents.");                    
                    
                    XmlDocument actionXml = new XmlDocument();
                    try
                    {
                        actionXml.Load(fileName);
                    }
                    catch (Exception ex)
                    {
                        WriteLog("Exception occurred while trying to create open the custom action XML: " + fileName + "\n" + ex.Data);
                        return InstallerReturnValue.Exception;
                    }

                    //XML file loaded. Now search for an existing custom action
                    XmlNodeList actionDescriptions = IntegrationKitUtilities.GetXmlNodeList(actionXml, "./ActionDescription");
                    if (actionDescriptions == null)
                    {
                        WriteLog("Custom action XML file exists but did not contain any ActionDescription nodes. Replacing content of the file.");
                        string content = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>" + actionContentXml.OuterXml.ToString();
                        if (IntegrationKitUtilities.ExportTextFileNoDialog(fileName, content) == false)
                        {
                            WriteLog("Could not create the custom action form XML file (" + fileName + "). Cannot continue.");
                            return InstallerReturnValue.Error;
                        }
                    }
                    else
                    {
                        // There is already some content in the XML file. Need to parse and see if our action exists or if our action
                        //  contains a group and our group exists

                        WriteLog("Custom action XML file exists and has ActionDescription nodes. Checking to see if this action exists.");
                        // do an XML query on the display name to see if it exists in the XML
                        string newActionDisplayName = IntegrationKitUtilities.GetXmlAttribute(actionContentXml, "DisplayName");
                        if (string.IsNullOrEmpty(newActionDisplayName))
                        {
                            WriteLog("Display name for new action not found. Cannot continue.");
                            return InstallerReturnValue.Error;
                        } 
                        XmlNode existingAction = IntegrationKitUtilities.GetXmlNode(actionXml, "./ActionDescription[@DisplayName='" + newActionDisplayName + "']");

                        if (existingAction == null)
                        {
                            //this action does not exist in the current XML, so add it.
                            WriteLog("Current action menu XML file does not contain this action. Adding it.");
                    
                            actionXml.ImportNode(actionContentXml, true);
                            actionXml.AppendChild(actionContentXml);
                        }
                        else
                        {
                            //this action exists in the XML.  Check to see if this is a group, and if so, check further down
                            //in case there are child nodes that need to be added.

                            WriteLog("Current action menu XML file already contains this action. Checking any child nodes.");

                            if (string.Compare(IntegrationKitUtilities.GetXmlAttribute(existingAction, "Class"), "Group", StringComparison.InvariantCultureIgnoreCase) == 0)
                            {
                                //this is a group, so check any child elements for the same name as our intended action
                                XmlNode newChild = IntegrationKitUtilities.GetXmlNode(actionContentXml, "./ActionGroups/ActionDescription");
                                if (newChild == null)
                                {
                                    WriteLog("Found existing ActionDescription with class=Group, but child 'ActionDescription' element not found in XML. Cannot continue.");
                                    return InstallerReturnValue.Error;
                                } 
                                string newChildActionDisplayName = IntegrationKitUtilities.GetXmlAttribute(newChild, "DisplayName");
                                if (string.IsNullOrEmpty(newChildActionDisplayName))
                                {
                                    WriteLog("Display name for new action not found. Cannot continue.");
                                    return InstallerReturnValue.Error;
                                }
                                
                                XmlNode existingGroup = IntegrationKitUtilities.GetXmlNode(existingAction, "./ActionGroups");
                                if (existingGroup == null)
                                {
                                    WriteLog("Found existing ActionDescription with class=Group, but 'ActionGroups' element not found in XML. Cannot continue.");
                                    return InstallerReturnValue.Error;
                                }
                                XmlNode existingChildAction = IntegrationKitUtilities.GetXmlNode(existingGroup, "./ActionDescription[@DisplayName='" + newChildActionDisplayName + "']");
                                if (existingChildAction == null)
                                {
                                    //this action does not exist in the current XML, so add it.
                                    WriteLog("Current action menu XML file does not contain the child action. Adding the child node.");
                                    XmlNode imported = actionXml.ImportNode(newChild, true);
                                    existingGroup.AppendChild(imported);

                                }
                                else
                                {
                                    //This action already exists. We may need to update it, so replace the existing content with the new content.
                                    //Replacing is faster than having to compare all the content.
                                    WriteLog("Current action menu XML file already contains this action. Replacing the content.");
                                    XmlNode imported = actionXml.ImportNode(newChild, true);
                                    if (imported == null)
                                    {
                                        WriteLog("An error occurred when importing the new action menu element into the existing child action. Cannot continue.");
                                        return InstallerReturnValue.Error;
                                    }
                                    existingGroup.ReplaceChild(imported, existingChildAction);

                                }
                            }
                            else
                            {
                                // This is not a group. Since the name is the same, this action already exists. 
                                // We may need to update it, so replace the existing content with the new content.
                                // Replacing is faster than having to compare all the content.
                                WriteLog("Current action menu XML file already contains this action. Replacing the content.");
                                XmlNode imported = actionXml.ImportNode(actionContentXml, true);
                                if (imported == null)
                                {
                                    WriteLog("An error occurred when importing the new action menu element into the existing child action. Cannot continue.");
                                    return InstallerReturnValue.Error;
                                }
                                existingAction.ParentNode.ReplaceChild(imported, existingAction);
                            }

                        }
                        //now save the XML file
                        actionXml.Save(fileName);
                    }
                }
            }
            return InstallerReturnValue.Success;
        }

        private InstallerReturnValue RemoveCustomActionMenu(XmlNode node)
        {
            if (node == null)
            {
                WriteLog("Xml node passed in to AddCustomActionMenu was null. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            
            //Get the list of nodes where this will be applied. Each node contains NodeGuid and FileName child elements
            XmlNodeList actionNodes = IntegrationKitUtilities.GetXmlNodeList(node, ".//ActionXmlInfo/Nodes");
            if (actionNodes == null)
            {
                WriteLog("Custom action XML did not contain info about the custom action nodes (ActionXmlInfo). Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }

            //Now, for each child node, update the existing file 
            foreach (XmlNode actionNode in actionNodes)
            {
                //get the contents of the XML file
                XmlNode actionContentXml = IntegrationKitUtilities.GetXmlNode(node, ".//ActionXmlContent/ActionDescription");
                if (actionContentXml == null)
                {
                    WriteLog("Custom action XML did not contain info about the custom action XML file (ActionXmlContent). Cannot continue.");
                    return InstallerReturnValue.Error;
                }

                DirectoryInfo actionDir = GetCustomActionDir(node);
                if (actionDir == null)
                {
                    WriteLog("Error! Could not get the path to the custom action XML directory.");
                    return InstallerReturnValue.Error; 
                }
                
                //get the XML node and filename info
                string actionXmlFile = IntegrationKitUtilities.GetXmlNodeValue(node, ".//FileName");
                if (actionXmlFile == null)
                {
                    WriteLog("Could not get the file name of the action XML file. Cannot continue.");
                    return InstallerReturnValue.Error;
                }

                //check to see if the file exists
                string fileName = actionDir + "\\" + actionXmlFile;
                if (File.Exists(fileName) == false)
                {
                    //nothing to do - file doesn't exist
                    WriteLog("Custom actions XML file (" + fileName + ") does not exist. Skipping.");
                    continue;
                }
                
                //the file exists. Open it and load the XML
                XmlDocument actionXml = new XmlDocument();
                try
                {
                    WriteLog("Loading the custom actions XML file (" + fileName + ").");
                    actionXml.Load(fileName);
                }
                catch (Exception ex)
                {
                    WriteLog("Exception occurred while trying to create open the custom action XML: " + fileName + "\n" + ex.Data);
                    return InstallerReturnValue.Exception;
                }

                //get a list of all the top level ActionDescription nodes (so we can count the total number of actions in the file). 
                XmlNodeList actionDescriptions = IntegrationKitUtilities.GetXmlNodeList(actionXml, "/ActionDescription");
                if (actionDescriptions == null)
                {
                    //XML doesn't contain any actions - go ahead and delete the file
                    try
                    {
                        WriteLog("The file does not have any actions. Removing the file");
                        File.Delete(fileName);
                        continue;
                    }
                    catch (Exception ex)
                    {
                        WriteLog("Exception occurred trying to delete the file: " + fileName + "\n" + ex.Data);
                        return InstallerReturnValue.Exception;
                    }
                }

                // There is already some content in the XML file 
                // Need to parse and see if our action exists or if our action contains a group and our group exists
                WriteLog("Custom action XML file exists and has ActionDescription nodes. Checking to see if this action exists.");
                string newActionDisplayName = IntegrationKitUtilities.GetXmlAttribute(actionContentXml, "DisplayName");
                if (string.IsNullOrEmpty(newActionDisplayName))
                {
                    WriteLog("Could not get the display name of the custom action to be removed. Cannot continue.");
                    return InstallerReturnValue.Error;
                } 
                //find the specific action matching the one we are trying to remove
                XmlNode existingAction = IntegrationKitUtilities.GetXmlNode(actionXml, "/ActionDescription[@DisplayName='" + newActionDisplayName + "']");
                
                if (existingAction == null)
                {
                    WriteLog("The action does not currently exist in this XML file. No action needed.");
                    continue;
                }
                
                //This action exists in the XML.  Check to see if this is a group, and if so, check further down 
                //inside the group in case there are child nodes that need to be added.
                if (string.Compare(IntegrationKitUtilities.GetXmlAttribute(existingAction, "Class"), "Group", StringComparison.InvariantCultureIgnoreCase) == 0)
                {
                    //this is a group, so check any child elements for the same name as our intended action
                    XmlNode newChild = IntegrationKitUtilities.GetXmlNode(actionContentXml, "./ActionGroups/ActionDescription");
                    if (newChild == null)
                    {
                        WriteLog("This was a group but could not get the XML element for the child ActionDescription node. Cannot continue.");
                        return InstallerReturnValue.Error;
                    }
                    string newChildActionDisplayName = IntegrationKitUtilities.GetXmlAttribute(newChild, "DisplayName");
                    if (string.IsNullOrEmpty(newChildActionDisplayName))
                    {
                        WriteLog("Could not get the display name of the custom action child node to be removed. Cannot continue.");
                        return InstallerReturnValue.Error;
                    } 
                    
                    XmlNode existingGroup = IntegrationKitUtilities.GetXmlNode(existingAction, "./ActionGroups");
                    if (existingGroup == null)
                    {
                        WriteLog("This was a group but could not get the XML element for the ActionGroups node. Cannot continue.");
                        return InstallerReturnValue.Error;
                    }

                    XmlNode existingChildAction = IntegrationKitUtilities.GetXmlNode(existingGroup, "./ActionDescription[@DisplayName='" + newChildActionDisplayName + "']");
                    if (existingChildAction == null)
                    {
                        WriteLog("The action does not currently exist in this XML file. No action needed.");
                        continue;
                    }

                    //This action already exists. Remove the existing action.
                    WriteLog("Removing the action from the group.");
                    existingGroup.RemoveChild(existingChildAction);
                    actionXml.Save(fileName);

                    //now check to see if the group has any children left. If not, remove the group/action.
                    if (existingGroup.HasChildNodes == false)
                    {
                        if (actionDescriptions.Count == 1)
                        {
                            //If there's only one main action, we can delete the whole file
                            try
                            {
                                WriteLog("The file does not have any remaining actions. Removing the file");
                                File.Delete(fileName);
                                continue;
                            }
                            catch (Exception ex)
                            {
                                WriteLog("Exception occurred trying to delete the file: " + fileName + "\n" + ex.Data);
                                return InstallerReturnValue.Exception;
                            }
                        }
                        else
                        {
                            //there is more than one action, so we can only delete this action, not the file
                            actionXml.RemoveChild(existingAction);
                            actionXml.Save(fileName);
                        }
                    }
                    //else the group has more child nodes, so don't remove it.
                }
                else
                {
                    // This is not a group. Since the name is the same, this action exists, so remove it
                    if (actionDescriptions.Count == 1)
                    {
                        //If there's only one action, we can delete the whole file
                        try
                        {
                            WriteLog("The file does not have any remaining actions after removing this one. Removing the file");
                            File.Delete(fileName);
                            continue;
                        }
                        catch (Exception ex)
                        {
                            WriteLog("Exception occurred trying to delete the file: " + fileName + "\n" + ex.Data);
                            return InstallerReturnValue.Exception;
                        }
                    }
                    else
                    {
                        //there is more than one, so we can only delete this action, not the file
                        WriteLog("Removing the action.");
                        actionXml.RemoveChild(existingAction);
                        actionXml.Save(fileName);
                    } 
                }
            }  // --> end foreach

            return InstallerReturnValue.Success;
        }

        private InstallerReturnValue AddCustomActionForm(XmlNode node)
        {
            // This method just checks to see if the file exists. 
            // If it doesn't, the file is created. If it does exist, it replaces the file.

            if (IntegrationKitUtilities.IsValidXmlElement(node) == false)
            {
                WriteLog("node parameter passed in to ProcessCustomAction was not a valid XML element. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }

            DirectoryInfo extensionsDir = GetExtensionsDir(node);
            if (extensionsDir == null)
            {
                WriteLog("Error! Could not get the path to the Extensions directory.");
                return InstallerReturnValue.Error;
            }

            string baseDir = extensionsDir.FullName + "Forms\\";
            if ((string.IsNullOrEmpty(baseDir) == false) && (Directory.Exists(baseDir) == false))
            {
                DirectoryInfo formsDir = Directory.CreateDirectory(baseDir);
                if (baseDir == null)
                {
                    WriteLog("Error! Could not find base Extensions directory at: " + baseDir);
                    return InstallerReturnValue.Error; ;
                }
            }
            
            //get the XML node and filename info
            XmlNode actionFormContentXml = IntegrationKitUtilities.GetXmlNode(node, ".//ActionFormContent/Form");
            if (actionFormContentXml == null)
            {
                WriteLog("Could not get content XML for form. Cannot continue.");
                return InstallerReturnValue.Error;
            }

            string fileName = IntegrationKitUtilities.GetXmlNodeValue(node, ".//ActionFormInfo/FileName");
            if (string.IsNullOrEmpty(fileName) == true)
            {
                WriteLog("Error! Could not get the target XML filename for the form XML.");
                return InstallerReturnValue.Error;
            }
            if (File.Exists(baseDir + "\\" + fileName) == true)
            {
                //file exists, so delete it.
                try
                {
                    File.Delete(baseDir + "\\" + fileName);
                }
                catch (Exception ex)
                {
                    WriteLog("Exception occurred trying to delete the file: " + baseDir + "\\" + fileName + "\n" + ex.Data);
                    return InstallerReturnValue.Exception;
                }
            }

            string content = "<SmsFormData FormatVersion=\"1.0\" xmlns=\"http://schemas.microsoft.com/SystemsManagementServer/2005/03/ConsoleFramework\">";
            content += actionFormContentXml.OuterXml.ToString() + "</SmsFormData>";

            if (IntegrationKitUtilities.ExportTextFileNoDialog(baseDir + "\\" + fileName, content) == false)
            {
                WriteLog("Could not create the custom action form XML file (" + baseDir + "\\" + fileName + "). Cannot continue.");
                return InstallerReturnValue.Error;
            }


            return InstallerReturnValue.Success;
        }

        private InstallerReturnValue RemoveCustomActionForm(XmlNode node)
        {
            if (IntegrationKitUtilities.IsValidXmlElement(node) == false)
            {
                WriteLog("node parameter passed in to ProcessCustomAction was not a valid XML element. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            DirectoryInfo extensionsDir = GetExtensionsDir(node);
            if (extensionsDir == null)
            {
                WriteLog("Error! Could not get the path to the Extensions directory.");
                return InstallerReturnValue.Error;
            }

            string baseDir = extensionsDir.FullName + "Forms\\";
            if (Directory.Exists(baseDir) == false)
            {
                WriteLog("Error! Could not find base Extensions directory at: " + baseDir);
                return InstallerReturnValue.Error; ;
            }

            string fileName = IntegrationKitUtilities.GetXmlNodeValue(node, ".//ActionFormInfo/FileName");
            if (string.IsNullOrEmpty(fileName) == true)
            {
                WriteLog("Error! Could not get the target XML filename for the form XML.");
                return InstallerReturnValue.Error;
            }
            if (File.Exists(baseDir + "\\" + fileName) == true)
            {
                //file exists, so delete it.
                try
                {
                    File.Delete(baseDir + "\\" + fileName);
                }
                catch (Exception ex)
                {
                    WriteLog("Exception occurred trying to delete the file: " + baseDir + "\\" + fileName + "\n" + ex.Data);
                    return InstallerReturnValue.Exception;
                }
            }
            return InstallerReturnValue.Success;
        }

        private InstallerReturnValue ProcessCustomAction(XmlNode node, string action)
        {
            //WriteLog("Now in ProcessCustomAction()"); 
            if (IntegrationKitUtilities.IsValidXmlElement(node) == false)
            {
                if (node.NodeType == XmlNodeType.Comment)
                {
                    //WriteLog("Node was a comment - skipping.");
                    return InstallerReturnValue.Success;
                }
                WriteLog("node parameter passed in to ProcessCustomAction was not a valid XML element. Cannot continue.");
                return InstallerReturnValue.InvalidParameter;
            }
            //if (Connection == null)
            //{
            //    WriteLog("Connection to Configuration Manager server is not valid. Cannot continue.");
            //    return InstallerReturnValue.ConnectionInvalid;
            //}
            
            string ID = IntegrationKitUtilities.GetXmlAttribute(node, "ID");
            
            if (string.Compare(action, "Create", StringComparison.OrdinalIgnoreCase) == 0)
            {
                InstallerReturnValue retVal = AddCustomActionMenu(node);
                if (retVal != InstallerReturnValue.Success)
                {
                    WriteLog("AddCustomActionMenu returned an error. Cannot continue.");
                    return InstallerReturnValue.Error;
                }
                else
                {
                    WriteLog("Successfully added the custom action menu XML data.");
                }

                InstallerReturnValue retVal2 = AddCustomActionForm(node);
                if (retVal2 != InstallerReturnValue.Success)
                {
                    WriteLog("AddCustomActionMenu returned an error. Cannot continue.");
                    return InstallerReturnValue.Error;
                }
                else
                {
                    WriteLog("Successfully added the custom action form XML data.");
                }


            }
            else if (string.Compare(action, "Delete", StringComparison.OrdinalIgnoreCase) == 0)
            {

                InstallerReturnValue retVal = RemoveCustomActionMenu(node);
                if (retVal != InstallerReturnValue.Success)
                {
                    WriteLog("RemoveCustomActionMenu returned an error. Cannot continue.");
                    return InstallerReturnValue.Error;
                }
                else
                {
                    WriteLog("Successfully removed the custom action menu XML data.");
                }

                InstallerReturnValue retVal2 = RemoveCustomActionForm(node);
                if (retVal2 != InstallerReturnValue.Success)
                {
                    WriteLog("RemoveCustomActionForm returned an error. Cannot continue.");
                    return InstallerReturnValue.Error;
                }
                else
                {
                    WriteLog("Successfully removed the custom action menu XML data.");
                }
                //WriteLog("Finding the folder on the Config Mgr server");

            }
            else if (string.Compare(action, "Update", StringComparison.OrdinalIgnoreCase) == 0)
            {
                //
                //
                //
                //update folder code to go here
                //
                //
                //
            }
            else
            {
                WriteLog("Invalid XML element name specified in ProcessCustomAction: " + node.Name);
                return InstallerReturnValue.InvalidParameter;
            }
            return InstallerReturnValue.Success;
        }



        #endregion

        #region Other Utils


        private string ParseRelativePath(string filePath, XmlNode pathNode)
        {
            if (pathNode == null)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "pathNode");
            }

            string isRelativeAttribute = IntegrationKitUtilities.GetXmlAttribute(pathNode, "IsRelative");
            if (string.IsNullOrEmpty(isRelativeAttribute))
            {
                return filePath;
            }
            bool isRelativePath;
            if (bool.TryParse(isRelativeAttribute, out isRelativePath) == false)
            {
                return filePath;
            }
            if (isRelativePath == false)
            {
                return filePath;
            }

            string pathRelativeTo = IntegrationKitUtilities.GetXmlAttribute(pathNode, "RelativeTo");
            if (string.IsNullOrEmpty(pathRelativeTo))
            {
                return filePath;
            }

            try
            {
                string prepend = string.Empty;

                WriteLog("Path to file is relative to: '" + pathRelativeTo + "'");

                //strip off leading path separator if it exists
                if (filePath.StartsWith("\\"))
                {
                    filePath = filePath.Substring(1);
                }

                //===[ begin modifications ]=================================
                // Modified 9/10/08 by rhearn
                // - Added new code for x64 detection and redirection of registry keys to Wow6432Node key

                string smsBaseRegKey = string.Empty;
                string smsBaseRegKey64 = string.Empty;

                smsBaseRegKey = @"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\SMS";
                smsBaseRegKey64 = @"SOFTWARE\Microsoft\SMS";
                

                //===[ end modifications ]=================================



                switch (pathRelativeTo)
                {
                    case "WaikRootDir":
                        prepend = GetWaikPath();
                        if (string.IsNullOrEmpty(prepend))
                        {
                            WriteLog("Error! WAIK directory not found!");
                            return null;
                        }
                        prepend += "\\";
                        break;

                    case "ConfigMgrLocalInstallDir":

                        prepend = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Installation Directory");
                        
                        if (string.IsNullOrEmpty(prepend))
                        {
                            WriteLog("Error! ConfigMgrLocalInstallDir property value was not found in the registry.");
                            return null;
                        }
                        prepend += "\\";
                        
                        break;

                    case "AdminUILocalInstallDir":
                        // modified 3/3/09 by rhearn
                        // Fixed an issue where using the "UI Installation Directory" key as the source for the AdminUI directory
                        // was not accurate, because SMS2003 upgrades to SCCM 2007 have this key pointing to the base SCCM dir instead
                        //
                        // The new logic to this process is reversed: 
                        //  - If the "Installation Directory" key exists, append "\AdminUI", otherwise use the "UI Installation Directory"

                        //prepend = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Setup", "UI Installation Directory");
                        prepend = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Installation Directory");
                        
                        if (string.IsNullOrEmpty(prepend))
                        {
                            WriteLog("'Installation Directory' value was not found in the registry. Trying 'UI Installation Directory'");
                            //prepend = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Installation Directory");
                            prepend = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Setup", "UI Installation Directory");

                            if (string.IsNullOrEmpty(prepend))
                            {
                                WriteLog("Error! 'UI Installation Directory' value was not found in the registry.");
                                return null;
                            }
                            else
                            {
                                //prepend += "\\AdminUI\\";
                                prepend += "\\";
                            }
                        }
                        else
                        {
                            prepend += "\\AdminUI\\"; 
                            //prepend += "\\";
                        }
                        break;

                    case "SiteUncShare":

                        siteCode = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Site Code");
                        serverName = IntegrationKitUtilities.GetConfigMgrRegistryStringValue("Identification", "Site Server");

                        if ((string.IsNullOrEmpty(siteCode)) ||
                            (string.IsNullOrEmpty(serverName)))
                        {
                            WriteLog("Error! 'Site Code' and/or 'Server' property values were not found in the registry. Cannot determine value for 'SiteUncShare'");
                            return null;
                        }
                        prepend = @"\\" + serverName + @"\SMS_" + siteCode + @"\";
                        break;

                    case "SystemDir":
                        prepend = System.Environment.SystemDirectory;
                        if (string.IsNullOrEmpty(prepend))
                        {
                            WriteLog("Error! Could not determine value for 'SystemDir'.");
                            return null;
                        }
                        break;

                    case "SystemDrive":
                        prepend = System.Environment.GetEnvironmentVariable("SystemDrive");
                        if (string.IsNullOrEmpty(prepend))
                        {
                            WriteLog("Error! Could not determine value for 'SystemDrive'.");
                            return null;
                        }
                        break;

                    case "SystemRoot":
                        prepend = System.Environment.GetEnvironmentVariable("SystemRoot");
                        if (string.IsNullOrEmpty(prepend))
                        {
                            WriteLog("Error! Could not determine value for 'SystemRoot'.");
                            return null;
                        }
                        break;

                    case "ProgramFiles":
                        prepend = System.Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
                        if (string.IsNullOrEmpty(prepend))
                        {
                            WriteLog("Error! Could not determine value for 'ProgramFiles'.");
                            return null;
                        }
                        break;

                    case "Temp":
                        prepend = System.Environment.GetEnvironmentVariable("TEMP");
                        if (string.IsNullOrEmpty(prepend))
                        {
                            WriteLog("Error! Could not determine value for 'Temp'.");
                            return null;
                        }
                        break;

                    case "Nothing":
                        break;

                    default:
                        break;

                }
                if (string.IsNullOrEmpty(prepend))
                {
                    WriteLog("ParseRelativePath() is returning : " + filePath);
                    return filePath;
                }
                else
                {
                    WriteLog("Relative path was translated to '" + prepend + filePath + "'");
                    return prepend + filePath;
                }
            }
            catch
            {
                WriteLog("Error! Exception occurred while parsing the relative path.");
                return null;
            }
        }
             
        private string GetObjectInstanceIdFromXml(string itemID, NodeType objectType)
        {
            if (string.IsNullOrEmpty(itemID))
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "itemID");
            }
            if (objectType < 0)
            {
                throw new System.ArgumentException(Properties.Resources.Error_InvalidParameter, "objectType");
            }
            try
            {
                string nodeName = Enum.GetName(typeof(NodeType), objectType);
                string instanceID = string.Empty;
                string query = "//" + nodeName + "[@ID='" + itemID + "']";
                
                //WriteLog("GetObjectInstanceIdFromXml(): Querying XML Log for the node: " + query);

                switch (nodeName)
                {
                    case "Folder":
                        query += "/ContainerNodeID";
                        break;
                    
                    case "Advertisement":
                        query += "/AdvertisementID";
                        break;

                    case "Driver":
                    case "SoftwareUpdate":
                    case "DcmBaseline":
                    case "DcmConfigurationItem":
                        query += "/CI_UniqueID";
                        break;

                    //case NodeType.DeviceSettingPackage:
                    case "OSImagePackage":
                    case "DriverPackage":
                    case "BootImagePackage":
                    case "Package":
                    case "SMS_TaskSequencePackage":
                        query += "/PackageID";
                        break;

                    case "Query":
                        query += "/QueryID";
                        break;

                    case "Report":
                        query += "/ReportID";
                        break;

                    case "DriverCategory":
                        query += "/CategoryInstance_UniqueID";
                        break;

                    case "Collection":
                        query += "/CollectionID";
                        break;

                    case "TaskSequence":
                        query = null;
                        break;


                    //case NodeType.MeteredProductRule:
                    //    query += "RuleID";
                    //    break;

                    //case NodeType.StateMigration:
                    //    query += "MigrationID";
                    //    break;

                    default:
                        query = null;
                        break;
                }
                instanceID = IntegrationKitUtilities.GetXmlNodeValue(InstalledComponentsXml, query);
                if (string.IsNullOrEmpty(instanceID))
                {
                    return null;
                }
                return instanceID;
            }
            catch
            {
                return null;
            }
        }

        private Nullable<int> GetParentFolderID(string parentFolderName, IntegrationKitUtilities.ContainerItemType containerNodeType)
        {
            Nullable<int> parentNodeID = null;
            if (string.IsNullOrEmpty(parentFolderName) == false)
            {
                //lookup by ID first in our own XML, then by name in the overall folder list
                string query = "//" + NodeType.Folder + "[@ID='" + parentFolderName + "']";
                WriteLog("Looking up parent folder in the Install Log XML: " + query);

                XmlNode parentFolderNode = IntegrationKitUtilities.GetXmlNode(InstalledComponentsXml, query);
                if (parentFolderNode == null)
                {
                    WriteLog("Parent folder specified was not found in the XML log from this installation: " + parentFolderName);

                    IResultObject parentFolderObject = IntegrationKitUtilities.GetFolderByName(Connection, parentFolderName, containerNodeType, null);
                    if (parentFolderObject == null)
                    {
                        WriteLog("Parent folder specified was not found during ProcessFolders: " + parentFolderName);
                        parentNodeID = null;
                    }
                    parentNodeID = IntegrationKitUtilities.GetROIntegerProperty(parentFolderObject, "ContainerNodeID");
                    if (parentNodeID.HasValue == false)
                    {
                        WriteLog("Folder ID for parent driver name " + parentFolderName + " was not found!");
                        parentNodeID = null;
                    }
                }
                else
                {
                    WriteLog("Parent folder found in the XML log from this installation");
                    string pID = IntegrationKitUtilities.GetXmlNodeValue(parentFolderNode, "ContainerNodeID");
                    if (string.IsNullOrEmpty(pID))
                    {
                        WriteLog("Error! Parent folder node did not contain a folder ID!");
                        parentNodeID = null;
                    }
                    int id = 0;
                    if (int.TryParse(pID, out id) == false)
                    {
                        WriteLog("Error! Parent folder node had a folder ID but it could not be parsed as an integer!");
                        parentNodeID = null;
                    }
                    else
                    {
                        WriteLog("Parent folder node has a folder ID of " + id);
                        parentNodeID = id;
                    }
                }
            }
            return parentNodeID;
        }


        #endregion

        #region Logging


        private XmlNode CreateXmlFromObject(IResultObject itemObject)
        {
            try
            {
                if (itemObject == null)
                {
                    throw new System.ArgumentException("itemObject", Properties.Resources.Error_InvalidParameter);
                }

                //WriteLog("Starting CreateXmlFromObject()");

                XmlElement topElement = InstalledComponentsXml.CreateElement("TopElement");

                itemObject.AutoCommit = true;
                itemObject.AutoRefresh = true;
                itemObject.Get();

                //WriteLog("  Properties:");
                //WriteLog("---------------");

                foreach (string propertyName in itemObject.PropertyNames)
                {
                    //WriteLog("\nProperty name: " + propertyName);

                    XmlElement newPropertyElement = InstalledComponentsXml.CreateElement(propertyName);

                    if ((itemObject[propertyName].IsArray) ||
                        (string.Compare(itemObject[propertyName].GetType().ToString(), "IResultObject", StringComparison.OrdinalIgnoreCase) == 0))
                    {
                        //List<IResultObject> newItemObject = itemObject.GetArrayItems(propertyName);

                        //WriteLog("Property '" + propertyName + " ' has :  " + newItemObject.Count + " sub-objects");

                        newPropertyElement.InnerText = "[CONTAINS EMBEDDED ARRAY OF ITEMS]";
                                
                        //List<IResultObject>.Enumerator newItemEnumerator = newItemObject.GetEnumerator();
                        //for (int i = 0; i < newItemObject.Count; i++)
                        //{
                        //    CreateXmlFromObject(newItemEnumerator.Current);
                        //    newItemEnumerator.MoveNext();
                        //}
                    }

                    AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData dataType = itemObject[propertyName].DataType;
                    string strType = Enum.GetName(typeof(AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData), dataType);
                    //WriteLog("         type: " + strType);
                    try
                    {
                        switch (dataType)
                        {
                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.String:
                                string propValue = itemObject[propertyName].StringValue;
                                if ((string.IsNullOrEmpty(propValue) == false) && (propValue.Contains("<")))
                                {
                                    newPropertyElement.InnerText = "<![CDATA[" + propValue + "]]>";
                                }
                                else
                                {
                                    newPropertyElement.InnerText = propValue;
                                }
                                break;

                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.Long:
                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.InvariantLong:
                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.Integer:
                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.InvariantInteger:
                                newPropertyElement.InnerText = itemObject[propertyName].IntegerValue.ToString();
                                break;

                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.Boolean:
                                newPropertyElement.InnerText = itemObject[propertyName].BooleanValue.ToString();
                                break;

                            case AdminConsole.Schema.ManagementClassPropertyDescription.TypeOfData.DateTime:
                                newPropertyElement.InnerText = itemObject[propertyName].DateTimeValue.ToString();
                                break;

                            default:
                                WriteLog("\n\n-----------------------------------------------------------------\n\n");
                                WriteLog("  Unknown data type in object property: " + dataType.ToString());
                                WriteLog("  Property name: '" + propertyName + "' ");
                                WriteLog("\n\n---------------------------------------------------------------------\n\n");
                                break;
                        }
                    }
                    catch (Exception)
                    {
                        //ignore
                    }
                    //WriteLog("        value: " + newPropertyElement.InnerText);
                    //WriteLog("---------------------------");

                    newPropertyElement.SetAttribute("Type", strType);

                    //WriteLog("\n\nContents of the new node: \n" + newPropertyElement.OuterXml);

                    topElement.AppendChild(newPropertyElement);
                    //WriteLog("\n\nContents of the new top element: \n" + topElement.OuterXml);
                }
               
                //WriteLog("Done adding properties.");
                XmlNode topNode = topElement;
                if (topNode.HasChildNodes == false)
                {
                    //should have child nodes - this must be an error
                    //WriteLog("No child nodes found for topNode!");
                    return null;
                }
                //WriteLog("Child nodes found: " + topNode.ChildNodes.Count);
                return topNode;
            }
            catch (SmsQueryException qex)
            {
                WriteLog("Exception occurred in CreateXmlFromObject() : " + qex.ExtendStatusErrorCode + "\n" + qex.Details + "\n" + qex.Data + "\n" + qex.TargetSite + "\n" + qex.InnerException + "\n" + qex.Message + "\n" + qex.StackTrace);
                return null;
            }
            catch (Exception ex)
            {
                WriteLog("Exception occured in CreateXmlFromObject().\n" + ex.Message);
                return null;
            }
        }

        private void WriteXmlLog(NodeType nodeType, IResultObject nodeObject, string objectID)
        {
            //WriteLog("Starting WriteXmlLog()");

            XmlNode log = IntegrationKitUtilities.GetXmlNode(InstalledComponentsXml, "//InstallationLog");
            if (log == null)
            {
                WriteLog("InstalledComponentsXml not found"); 
                return;
            }
            if (string.IsNullOrEmpty(objectID))
            {
                WriteLog("objectID was null"); 
                return;
            }
            if (nodeObject == null)
            {
                WriteLog("nodeObject was null"); 
                return;
            }
            
            string nodeName = Enum.GetName(typeof(NodeType), nodeType);
            
            //WriteLog("nodeName = " + nodeName);

            XmlElement newElement = InstalledComponentsXml.CreateElement(nodeName);
            newElement.SetAttribute("ID", objectID);
            XmlNode newNode = newElement;

            XmlNode elementContents = CreateXmlFromObject(nodeObject);
            
            //WriteLog("The node returned : " + elementContents.NodeType + "\n\n");

            if (elementContents == null)
            {
                WriteLog("The node returned from CreateXmlFromObject() was invalid. \n\n" + elementContents.OuterXml+ "\n\n"); 
                return;
            }
            //WriteLog("CreateXmlFromObject() returned a valid node.\n\n" + elementContents.OuterXml + "\n\n");

            if (elementContents.HasChildNodes == false)
            {
                WriteLog("The node returned from CreateXmlFromObject() was invalid. It had no child nodes\n\n");
                return;
            }
            //WriteLog("The node returned has " + elementContents.ChildNodes.Count + " child nodes\n\n");
                
            for (int i = 0; i < elementContents.ChildNodes.Count; i++)
            {
                newNode.AppendChild(elementContents.ChildNodes[i]);
            }
            string query = "//" + nodeName + "[@ID='" + objectID + "']";
            
            //WriteLog("Querying the log for an existing node: " + query);
            
            XmlNode prevLogItem = IntegrationKitUtilities.GetXmlNode(log, query);
            if (prevLogItem == null)
            {
                //WriteLog("Appending new item to the log: \n" + newNode.OuterXml);
                log.AppendChild(newElement);
            }
            else
            {
                //WriteLog("Replacing existing item in the log: \n" + newNode.OuterXml);
                log.ReplaceChild(newNode, prevLogItem);
            }            



        }

        private XmlNode LookupObjectFromXmlLog(NodeType nodeType, string objectID)
        {
            //WriteLog("LookupObjectFromXmlLog(): trying to find object ID : " + objectID);

            


            XmlNode log = IntegrationKitUtilities.GetXmlNode(InstalledComponentsXml, "//InstallationLog");
            if (log == null)
            {
                WriteLog("Error! LookupObjectFromXmlLog(): InstalledComponentsXml object was null!");
                return null;
            }

            string nodeName = Enum.GetName(typeof(NodeType), nodeType);
            
            XmlNode logItem = IntegrationKitUtilities.GetXmlNode(log, "//" + nodeName + "[@ID='" + objectID + "']");
            if (logItem == null)
            {
                WriteLog("//" + nodeName + "[@ID='" + objectID + "']  was not found in the installed components list");
                return null;
            }
            else
            {
                WriteLog("Found the Xml node in the installed components list. Returning.");
                return logItem;
            }       

        }

        private void WriteLog(string message)
        {
            try
            {
                //Console.WriteLine("\n\nWriteLog:" + message);

                string logFile = string.Empty;
                if (string.IsNullOrEmpty(LogDir))
                {
                    //Console.WriteLine("\n\nWriteLog: Setting logFile to LOGFILENAME: " + LOGFILENAME); 
                    logFile = LOGFILENAME;
                }
                else
                {
                    //Console.WriteLine("\n\nWriteLog: LogDir is: " + LogDir); 
                    DirectoryInfo di = new DirectoryInfo(LogDir);
                    
                    logFile = di.FullName + "\\" + LOGFILENAME;
                }
                message = string.Format(CultureInfo.CurrentCulture, DateTime.Now.ToString() + " :: " + message);
                //Console.WriteLine("\n\nWriteLog:" + message);
                //Console.WriteLine("\n\nWriteLog: Appending to LogString");
                LogString.AppendLine(message);
                SaveLogToFile(logFile, message + "\n", FileMode.Append);
            }
            catch
            {
                //DialogHelper.ShowMessageBox("Error writing to log file!");
                //throw;
                return;
            }


        }

        private void WriteError(string message)
        {
            try
            {
                string logFile = string.Empty;
                if (string.IsNullOrEmpty(LogDir))
                {
                    logFile = LOGFILENAME;
                }
                else
                {
                    DirectoryInfo di = new DirectoryInfo(LogDir);
                    
                    logFile = di.FullName + Path.DirectorySeparatorChar + LOGFILENAME;
                }

                string newMessage = string.Format(CultureInfo.CurrentCulture, DateTime.Now.ToString() + " :: " + message + "\n");
                LogString.AppendLine("================================================================================[ ERROR ]=================");
                LogString.AppendLine(newMessage);
                LogString.AppendLine("================================================================================[ ERROR ]=================");
                
                SaveLogToFile(logFile, "\n\n"+ newMessage + "\n\n", FileMode.Append);
            }
            catch
            {
                //DialogHelper.ShowMessageBox("Error writing to log file!");
                //throw;
                return;
            }


        }

        private void DumpSecondaryLog()
        {
            try
            {
                string logFile = string.Empty;
                if (string.IsNullOrEmpty(LogDir))
                {
                    logFile = LOGFILENAME;
                }
                else
                {
                    DirectoryInfo di = new DirectoryInfo(LogDir);

                    logFile = di.FullName + Path.DirectorySeparatorChar + LOGFILENAME;
                }

                if (LogFile != null)
                {
                    LogFile.Flush();
                    LogFile.Close();
                }
                FileStream fs = new FileStream(SECONDARYLOGFILE, FileMode.Open, FileAccess.Read, FileShare.ReadWrite, 8, true);
                StreamReader sr = new StreamReader(fs);
                string secLogString = sr.ReadToEnd();
                LogString.AppendLine("=====================================================");
                LogString.AppendLine(" Secondary Log info (from integration kit methods)");
                LogString.AppendLine(" ");
                LogString.Append(secLogString);
                LogString.AppendLine(" ");
                LogString.AppendLine("=====================================================");
                SaveLogToFile(logFile, "\n\n" + secLogString + "\n\n", FileMode.Append);
                fs.Close();
                sr.Close();
            }
            catch (Exception ex)
            {
                WriteError(ex.Message);
            }
        }

        private void SaveLogToFile(string fileName, string textString, FileMode mode)
        {
            string logFile = string.Empty;
            
            try
            {
                if (string.IsNullOrEmpty(fileName))
                {
                    return;
                }
                
                if (string.IsNullOrEmpty(LogDir))
                {
                    logFile = LOGFILENAME;
                }
                else
                {
                    DirectoryInfo di = new DirectoryInfo(LogDir);
                    
                    logFile = di.FullName + Path.DirectorySeparatorChar + fileName;
                }
                
                
                FileStream fs = new FileStream(fileName, mode, FileAccess.Write, FileShare.ReadWrite, 8, true);

                StreamWriter sw = new StreamWriter(fs);
                sw.Write(textString);
                sw.Close();
            }
            catch (IOException)
            {
                DialogHelper.ShowMessageBox("Unable to open log file : " + logFile);
                //throw;
            }
        }

        private void SetStatusMessage(string section, string statusMessage, InstallerReturnValue statusType, int pctComplete)
        {
            InstallerStatus current = new InstallerStatus();
            current.CurrentSection = section;
            current.PercentComplete = pctComplete;
            current.StatusMessage = statusMessage;
            current.StatusValue = statusType;
            Status = current;
        }

        #endregion


       

       
    }
}
